Check-in [beeeb45bbf]
Not logged in

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

Overview
Comment:Merge updates from HEAD Note that this branch currently does not fully support the new {expand} syntax. Updates to TclEvalScriptTokens and TclCompileScriptTokens are still to come.
Timelines: family | ancestors | descendants | both | dgp-refactor
Files: files | file ages | folders
SHA1: beeeb45bbf5e097d636382d4b3ff2ac82baf8645
User & Date: dgp 2004-02-07 05:47:59.000
Context
2004-02-18
22:30
Merge updates from HEAD. Ported support of {expand} syntax. check-in: 257d73b262 user: dgp tags: dgp-refactor
2004-02-07
05:47
Merge updates from HEAD Note that this branch currently does not fully support the new {expand} syn... check-in: beeeb45bbf user: dgp tags: dgp-refactor
2003-10-16
02:29
Merge updates from HEAD. check-in: 6eee5f37f0 user: dgp tags: dgp-refactor
Changes
Unified Diff Ignore Whitespace Patch
Changes to ChangeLog.
































































































































































































































































































































































































































































































































































































































































































































































































































































1
2
3
4
5
6
7
































































































































































































































































































































































































































































































































































































































































































































































































































































2003-10-15  Donal K. Fellows  <fellowsd@cs.man.ac.uk>

	* generic/tclCmdIL.c (SortInfo,etc): Reorganized so that SortInfo
	carries an array of integer indices instead of a Tcl list.  This
	nips shimmering problems in the bud and simplifies SelectObjFromSublist
	at the cost of making setup slightly more complex. [Bug 823768]

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







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
2004-02-06  Don Porter	<dgp@users.sourceforge.net>

	* doc/clock.n:	Removed reference to non-existent [file ctime].

2004-02-05  David Gravereaux <davygrvy@pobo.co>

	* docs/tclvars.n: Added clarification of the tcl_platform(debug)
	var that it only refers to the flavor of the C run-time, and not
	whether the core contains symbols.

2004-02-05  Don Porter	<dgp@users.sourceforge.net>

	* generic/tclFileName.c (SkipToChar):	Corrected CONST and
	type-casting issues that caused compiler warnings.

2004-02-04  Don Porter	<dgp@users.sourceforge.net>

	* generic/tclCmdAH.c (StoreStatData):	Removed improper refcount
	decrement of the varName parameter.  This error was causing
	segfaults following test cmdAH-28.7.

	* library/tcltest/tcltest.tcl:	Corrected references to
	non-existent $name variable in [cleanupTests]. [Bug 833637]

2004-02-03  Don Porter	<dgp@users.sourceforge.net>

	* library/tcltest/tcltest.tcl:	Corrected parsing of single
	command line argument (option with missing value) [Bug 833910]
	* library/tcltest/pkgIndex.tcl:	Bump to version 2.2.5.

2004-02-02  David Gravereaux <davygrvy@pobox.com>

	* generic/tclIO.c (Tcl_Ungets): Fixes improper filling of the
	channel buffer. This is the buffer before the splice. [Bug 405995]

2004-02-01  David Gravereaux <davygrvy@pobox.com>

	* tests/winPipe.test: more pass-thru commandline verifications.
	* win/tclWinPipe.c (BuildCommandLine): Special case quoting for
	'{' not required by the c-runtimes's parse_cmdline().
	* win/tclAppInit.c: Removed our custom setargv() in favor of
	the work provided by the c-runtime. [Bug 672938]

	* win/nmakehlp.c: defensive techniques to avoid static buffer
	overflows and a couple envars upsetting invokations of cl.exe
	and link.exe.  [Bug 885537]

	--------
	* tests/winPipe.test: Added proof that BuildCommandLine() is not
	doing the "N backslashes followed a quote -> insert N * 2 + 1
	backslashes then a quote" rule needed for the crt's
	parse_cmdline().
	* win/tclWinPipe.c: Fixed BuildCommandLine() to pass the new
	cases.

2004-01-30  David Gravereaux <davygrvy@pobox.com>

	* win/makefile.vc: Use the -GZ compiler switch when building for
	symbols.  This is supposed to emulate the release build better to
	avoid hiding problems that only show themselves in a release
	build.

2004-01-29  Vince Darley  <vincentdarley@users.sourceforge.net>

	* generic/tclPathObj.c: fix to [Bug 883143] in file normalization

2004-01-29  Vince Darley  <vincentdarley@users.sourceforge.net>

	* doc/file.n: 
	* generic/tclFCmd.c
	* generic/tclTest.c
	* library/init.tcl
	* mac/tclMacFile.c
	* tests/fileSystem.test: fix to [Bug 886352] where 'file copy
	-force' had inconsistent behaviour wrt target files with
	insufficient permissions, particular from vfs->native fs.
	Behaviour of '-force' is now always consistent (and now
	consistent with behaviour of 'file delete -force').  Added new
	tests and documentation and cleaned up the 'simplefs' test
	filesystem.
	
	* generic/tclIOUtil.c
	* unix/tclUnixFCmd.c
	* unix/tclUnixFile.c
	* win/tclWinFile.c: made native filesystems more robust to C code
	which asks for mount lists.
	
	* generic/tclPathObj.c: fix to [Bug 886607] removing warning/error
	with some compilers.
	
2004-01-28  Donal K. Fellows  <donal.k.fellows@man.ac.uk>

	* generic/tclObj.c (SetBooleanFromAny): Rewrite to do more
	efficient string->bool conversion.
	Many other minor whitespace/style fixes to this file too.

2004-01-27  David Gravereaux <davygrvy@pobox.com>

	* win/nmakehlp.c: Use '.\nul' as the sourcefile name instead of
	'nul' so VC 5.2 doesn't try searching the path for it and failing
	with a possible dialogbox popping up about having to add a CD to
	an empty drive.  Also added a SetErrorMode() call to disable any
	dialogs that cl.exe or link.exe might create.  [Bug 885537]

2004-01-22  Vince Darley  <vincentdarley@users.sourceforge.net>

	* doc/file.n: clarified documentation of 'file system' [Bug 883825]
	* tests/fCmd.test: improved test result in failure case.
	
2004-01-22  Vince Darley  <vincentdarley@users.sourceforge.net>

	* tests/fileSystem.test: 3 new tests
	* generic/tclPathObj.c: fix to [Bug 879555] in file normalization. 
	* doc/filename.n: small clarification to Windows behaviour with
	filenames like '.....', 'a.....', '.....a'.
	
	* generic/tclIOUtil.c: slight improvement to native cwd caching
	on Windows.

2004-01-21  David Gravereaux <davygrvy@pobox.com>

	* doc/Panic.3:  Mentions of 'panic' and 'panicVA' removed from
	the documentation.

2004-01-21  Vince Darley  <vincentdarley@users.sourceforge.net>

	* doc/FileSystem.3: 
	* generic/tcl.decls: 
	* generic/tclCmdAH.c
	* generic/tclDecls.h
	* generic/tclFCmd.c
	* generic/tclFileName.c
	* generic/tclFileSystem.h
	* generic/tclIOUtil.c
	* generic/tclInt.decls
	* generic/tclInt.h
	* generic/tclIntDecls.h
	* generic/tclPathObj.c
	* generic/tclStubInit.c
	* generic/tclTest.c
	* mac/tclMacFile.c
	* tests/fileName.test
	* tests/fileSystem.test
	* tests/winFCmd.test
	* unix/tclUnixFile.c
	* win/tclWin32Dll.c
	* win/tclWinFCmd.c
	* win/tclWinFile.c
	* win/tclWinInt.h
	
	Three main issues accomplished: (1) cleaned up variable names in
	the filesystem code so that 'pathPtr' is used throughout.  (2)
	applied a round of filesystem optimisation with better handling
	and caching of relative and absolute paths, requiring fewer
	conversions.  (3) clarifications to the documentation,
	particularly regarding the acceptable refCounts of objects.
	Some new tests added.  Tcl benchmarks show a significant
	improvement over 8.4.5, and on Windows typically a small
	improvement over 8.3.5 (Unix still appears to require
	optimisation).  TCL_FILESYSTEM_VERSION_2 introduced, but for
	internal use only.  There should be no public incompatibilities
	from these changes.  Thanks to dgp for extensive testing.
	
2004-01-19  David Gravereaux <davygrvy@pobox.com>

	* win/tclWinPipe.c (Tcl_WaitPid): Fixed a thread-safety problem
	with the process list.  The delayed cut operation after the wait
	was going stale by being outside the list lock.  It now cuts
	within the lock and does a locked splice for when it needs to
	instead.  [Bug 859820]

2004-01-18  Donal K. Fellows  <donal.k.fellows@man.ac.uk>

	* generic/tclCompile.c, generic/tclCompile.h: Two new opcodes,
	INST_LIST_INDEX_IMM and INST_LIST_RANGE_IMM, that have operand(s)
	of new type OPERAND_IDX4 which represents indexes into things like
	lists (and perhaps other things eventually.)
	* generic/tclExecute.c (TclExecuteByteCode): Implementation of the
	new opcodes.  INST_LIST_INDEX_IMM does a simple [lindex] with
	either front- or end-based simple indexing.  INST_LIST_RANGE_IMM
	does an [lrange] with front- or end-based simple indexing for both
	the reference to the first and last items in the range.
	* generic/tclCompCmds.c (TclCompileLassignCmd): Generate bytecode
	for the [lassign] command.

2004-01-17  David Gravereaux <davygrvy@pobox.com>

	* win/tclWinInit.c:  added #pragma comment(lib, "advapi32.lib")
	when compiling under VC++ so we don't need to specify it
	when linking.

2004-01-17  Donal K. Fellows  <donal.k.fellows@man.ac.uk>

	* generic/tclCmdIL.c (Tcl_LassignObjCmd): Add more shimmering
	protection for when the list is also one of the variables.

	BASIC IMPLEMENTATION OF TIP#57
	* generic/tclCmdIL.c (Tcl_LassignObjCmd): Implementation of the
	[lassign] command that takes full advantage of Tcl's object API.
	* doc/lassign.n: New file documenting the command.
	* tests/cmdIL.test (cmdIL-6.*): Test suite for the command.

2004-01-15  David Gravereaux <davygrvy@pobox.com>

	* win/tclWinReg.c:  Placed the requirement for advapi.lib into
	the object file itself with #paragma comment (lib, ...) when
	built with VC++.  This will simplify linking for users of the
	static library.

	* win/rules.vc:  Added new 'fullwarn' to the CHECKS commandline
	macro; sets $(FULLWARNINGS).

	* win/makefile.vc:  Removed 'advapi.lib' from $(baselibs).
	Added new logic to crank-up the warning levels for both compile
	and link when $(FULLWARNINGS) is set.  Some clean-up with how
	the resource files are built and how -DTCL_USE_STATIC_PACKAGES
	is sent when compiling the shells.

	* win/tclAppInit.c: Small change in how TCL_USE_STATIC_PACKAGES
	is used.

	* win/tcl.rc:
	* win/tclsh.rc: Some clean-up with how the resource files are
	built.  Fixed 'OriginalFilename' problem that still thought
	a debug suffix was still 'd', now is 'g'.

2004-01-14  Donal K. Fellows  <donal.k.fellows@man.ac.uk>

	* generic/tclDictObj.c (TraceDictPath, DictExistsCmd): Adjusted
	behaviour of [dict exists] so a failure to look up a dictionary
	along the path of dicts doesn't trigger an error.  This is how it
	was documented to behave previously...  [Bug 871387]

	* generic/tclDictObj.c: Assorted dict fixes from Peter Spjuth
	relating to [Bug 876170].
	(SetDictFromAny): Make sure that lists retain their ordering even
	when converted to dictionaries and back.
	(TraceDictPath): Correct object reference count handling!
	(DictReplaceCmd, DictRemoveCmd): Stop object leak.
	(DictIncrCmd,DictLappendCmd,DictAppendCmd,DictSetCmd,DictUnsetCmd): 
	Simpler handling of reference counts when assigning to variables.
	* tests/dict.test (dict-19.2): Memory leak stress test

2004-01-13  Don Porter	<dgp@users.sourceforge.net>

	* generic/tclCmdMZ.c (Tcl_SwitchObjCmd):  Silence compiler warnings.

	Patch 876451: restores performance of [return].  Also allows forms
	such as [return -code error $msg] to be bytecompiled.

	* generic/tclInt.h:	Factored Tcl_ReturnObjCmd() into two pieces:
	* generic/tclCmdMZ.c:	TclMergeReturnOptions(), which can parse the
	options to [return], check their validity, and create the
	corresponding return options dictionary, and TclProcessReturn(),
	which takes that return options dictionary and performs the
	[return] operation.

	* generic/tclCompCmds.c:	Rewrote TclCompileReturnCmd() to
	call TclMergeReturnOptions() at compile time so the return options
	dictionary is computed at compile time (when it is fully known).
	The dictionary is pushed on the stack along with the result, and
	the code and level values are included in the bytecode as operands.
	Also supports optimized compilation of un-[catch]ed [return]s from
	procs with default options into the INST_DONE instruction.
	
	* generic/tclExecute.c:	Rewrote INST_RETURN instruction to retrieve
	the code and level operands, pop the return options from the stack,
	and call TclProcessReturn() to perform the [return] operation.

	* generic/tclCompile.h:	New utilities include TclEmitInt4 macro
	* generic/tclCompile.c:	and TclWordKnownAtCompileTime().
	
	End Patch 876451.

	* generic/tclFileName.c (Tcl_GlobObjCmd):  Latest changes to
	management of the interp result by Tcl_GetIndexFromObj() exposed
	improper interp result management in the [glob] command procedure.
	Corrected by adopting the Tcl_SetObjResult(Tcl_NewStringObj) pattern.
	This stopped a segfault in test filename-11.36. [Bug 877677]

2004-01-13  Donal K. Fellows  <donal.k.fellows@man.ac.uk>

	* generic/tclIndexObj.c (Tcl_GetIndexFromObjStruct, Tcl_WrongNumArgs):
	Create fresh objects instead of using the one currently in the
	interpreter, which isn't guaranteed to be fresh and unshared. The
	cost for the core will be minimal because of the object cache, and
	this fixes [Bug 875395].

2004-01-12  Miguel Sofer <msofer@users.sf.net>

	* generic/tclCompExpr.c (CompileLandOrLorExpr): cosmetic changes. 

2004-01-12  Miguel Sofer <msofer@users.sf.net>

	* generic/tclCompExpr.c (CompileLandOrLorExpr): new logic, fewer
	instructions. As a side effect, the instructions INST_LOR and
	INST_LAND are now never used.
	* generic/tclExecute.c (INST_JUMP*): small optimisation; fix a
	bug in debug code.

2004-01-11  David Gravereaux <davygrvy@pobox.com>

	* win/tclWinThrd.c (Tcl_ConditionNotify): condPtr must be
	dereferenced to see if there are waiters else uninitialized
	datum is manipulated.  [Bug 849007 789338 745068]

2004-01-09  David Gravereaux <davygrvy@pobox.com>

	* generic/tcl.h: Renamed and deprecated #defines moved to within
	the #ifndef TCL_NO_DEPRECATED block.  This allows us to build Tcl
	to check for deprecated functions in use, such as panic() and
	Tcl_Ckalloc().  By request from DKF.  Extensions that build
	with -DTCL_NO_DEPRECATED now have these macros as restricted.
	***POTENTIAL INCOMPATIBILITY***

	* win/makefile.vc:
	* win/rules.vc:  Added -DTCL_NO_DEPRECATED usage to makefile.vc.
	Called like this:   nmake -af makefile.vc CHECKS=nodep

2004-01-09  Vince Darley  <vincentdarley@users.sourceforge.net>

	* generic/tclIOUtil.c: fix to infinite loop in 
	TclFinalizeFilesystem [Bug 873311]

2003-12-25  Mo DeJong  <mdejong@users.sourceforge.net>

	* win/tclWin32Dll.c (DllMain): Add HAVE_NO_SEH
	blocks in place of __try and __except statements
	to support gcc builds. This is needed after
	David's changes on 2003-12-21. [Tcl patch 858493]

2003-12-23  David Gravereaux <davygrvy@pobox.com>

	* generic/tclAlloc.c:	All uses of 'panic' (the macro) changed
	* generic/tclBasic.c:	to 'Tcl_Panic' (the function).  The
	* generic/tclBinary.c:	#define of panic in tcl.h clearly states
	* generic/tclCkalloc.c:	it is deprecated in the comments.
	* generic/tclCmdAH.c:	[Patch 865264]
	* generic/tclCmdIL.c:
	* generic/tclCmdMZ.c:
	* generic/tclCompCmds.c:
	* generic/tclCompExpr.c:
	* generic/tclCompile.c:
	* generic/tclConfig.c:
	* generic/tclDictObj.c:
	* generic/tclEncoding.c:
	* generic/tclEvent.c:
	* generic/tclExecute.c:
	* generic/tclHash.c:
	* generic/tclInterp.c:
	* generic/tclIO.c:
	* generic/tclIOCmd.c:
	* generic/tclIOUtil.c:
	* generic/tclListObj.c:
	* generic/tclLiteral.c:
	* generic/tclNamesp.c:
	* generic/tclObj.c:
	* generic/tclParse.c:
	* generic/tclPathObj.c:
	* generic/tclPkg.c:
	* generic/tclPreserve.c:
	* generic/tclProc.c:
	* generic/tclStringObj.c:
	* generic/tclTest.c:
	* generic/tclThreadAlloc.c:
	* generic/tclTimer.c:
	* generic/tclTrace.c:
	* generic/tclVar.c:
	* mac/tclMacChan.c:
	* mac/tclMacOSA.c:
	* mac/tclMacResource.c:
	* mac/tclMacSock.c
	* mac/tclMacThrd.c:
	* unix/tclUnixChan.c:
	* unix/tclUnixNotfy.c:
	* unix/tclUnixThrd.c:
	* unix/tclXtNotify.c:
	* win/tclWin32Dll.c:
	* win/tclWinChan.c:
	* win/tclWinFCmd.c:
	* win/tclWinNotify.c:
	* win/tclWinPipe.c:
	* win/tclWinSock.c:
	* win/tclWinThrd.c:

	* generic/tclInt.h:  Deprecated use of Tcl_Ckalloc changed to
	Tcl_Alloc in the TclAllocObjStorage macro.

2003-12-22  David Gravereaux <davygrvy@pobox.com>

	* win/nmakehlp.c:
	* win/rules.vc:  New feature for extensions that use rules.vc.
	Now reads header files for version strings.  No more hard coding
	TCL_VERSION = 8.5 and having to edit it when you swap cores.

	* win/makefile.vc: VERSION macro now set by reading tcl.h for it.

	* generic/tcl.h: Removed note that makefile.vc needs to have a
	version number changed.

2003-12-21  David Gravereaux <davygrvy@pobox.com>

	* win/tclWin32Dll.c: Structured Exception Handling added around
	Tcl_Finalize called from DllMain's DLL_PROCESS_DETACH.  We can't
	be 100% assured that Tcl is being unloaded by the OS in a stable
	condition and we need to protect the exit handlers should the
	stack be in a hosed state.  AT&T style assembly for SEH under
	MinGW has not been added yet.  This is a first part change for
	[Patch 858493]

2003-12-17  Daniel Steffen  <das@users.sourceforge.net>

	* generic/tclBinary.c (DeleteScanNumberCache): fixed crashing bug
	when numeric scan-value cache contains NULL value.

2003-12-17  Vince Darley  <vincentdarley@users.sourceforge.net>

	* generic/tclCmdAH.c: 
	* unix/tclUnixFile.c: 
	* win/tclWinFCmd.c: 
	* tests/fCmd.test: 
	* tests/fileSystem.test: 
	* doc/file.n: final fix to support for relative links and
	its implications on normalization and other parts of the
	filesystem code.  Fixes [Bug 859251] and some Windows
	problems with recursive file delete/copy and symbolic links.
	
2003-12-17  Vince Darley  <vincentdarley@users.sourceforge.net>

	* generic/tclPathObj.c: 
	* tests/fileSystem.test: fix and tests for [Bug 860402] in new 
	file normalization code.
	
2003-12-17  Zoran Vasiljevic  <zv@archiware.com>

	* generic/tclIOUtil.c: fixed 2 memory (object) leaks.
	This fixes Tcl Bug #839519.

	* generic/tclPathObj.c: fixed Tcl_FSGetTranslatedPath
	to always return properly refcounted path object.
	This fixes Tcl Bug #861515.

2003-12-16  Vince Darley  <vincentdarley@users.sourceforge.net>

	* tests/fCmd.test: marking fCmd-9.14.2, as nonPortable, since
	on Solaris one can change the name of the current directory
	with 'file rename'.
	* doc/FileSystem.3: clarified documentation on ownership
	of return objects/strings of some Tcl_FS* calls.

2003-12-16  Donal K. Fellows  <donal.k.fellows@man.ac.uk>

	* generic/tclThreadAlloc.c (binfo): Made variable file-local.

2003-12-15  David Gravereaux <davygrvy@pobox.com>

	* win/tcl.rc:
	* win/tclsh.rc: Slight modification to the STRINGIFY macro to
	support Borland's rc tool.

	* win/tclWinFile.c (TclpUtime) : utimbuf struct not a problem 
	with Borland.

	* win/tclWinTime.c (TclpGetDate) : Borland's localtime() has
	a slight behavioral difference.

	From Helmut Giese <hgiese@ratiosoft.com> [Patch 758097].

2003-12-14  David Gravereaux <davygrvy@pobox.com>

	* generic/tclInt.decls: commented-out entry for
	TclpCheckStackSpace, removing it from the Stubs table.  It's
	already declared in tclInt.h and labeled as a function that is
	not to be exported.  Regened tables.

2003-12-14  Donal K. Fellows  <donal.k.fellows@man.ac.uk>

	* generic/tclCmdMZ.c (Tcl_SwitchObjCmd): TIP#75 Implementation
	* tests/switch.test:	Can now get submatch information when
	* doc/switch.n:		using -regexp matching in [switch].

2003-12-14  Vince Darley  <vincentdarley@users.sourceforge.net>

	* generic/tclPathObj.c: complete rewrite of generic file 
	normalization code to cope with links followed by '..'.
	[Bug 849514], and parts of [859251]

2003-12-12  David Gravereaux <davygrvy@pobox.com>

	* win/tclWinChan.c: Win32's SetFilePointer() takes LONGs not
	DWORDs (a signed/unsigned mismatch).  Redid local vars to
	avoid all casting except where truly required.

2003-12-12  Vince Darley  <vincentdarley@users.sourceforge.net>

	* generic/tclCmdAH.c: fix to normalization of non-existent user
	name ('file normalize ~nobody') [Bug 858937]
	* doc/file.n: clarify behaviour of 'file link' when the target
	is not an absolute path.
	* doc/filename.n: correct documentation to say that Windows Tcl 
	does handle '~user', for recent Windows releases, and clarified
	distinction between MacOS 'classic' and MacOS X.
	* doc/glob.n: clarification of glob's behaviour when returning
	filenames starting with a '~'.
	
	* tests/fileSystem.test:
	* tests/fileName.test: new tests added for the normalization
	problem above and other recentlt reported issues.

	* win/tclWinFile.c: corrected unclear comments
	
	* unix/tclUnixFile.c: allow creation of relative links
	[Bug 833713]

2003-12-11  David Gravereaux <davygrvy@pobox.com>

	* win/tclWinSock.c (SocketThreadExitHandler) : added a
	TerminateThread fallback just in case the socket handler thread
	is really in a paused state.  This can happen when Tcl is being
	unloaded by the OS from an exception handler.  See MSDN docs on
	DllMain, it states this behavior.

2003-12-09  Jeff Hobbs  <jeffh@ActiveState.com>

	* unix/configure:
	* unix/tcl.m4: updated OpenBSD build configuration based on
	[Patch #775246] (cassoff)

2003-12-09  Donal K. Fellows  <donal.k.fellows@man.ac.uk>

	* unix/tclUnixPort.h:	#ifdef'd out declarations of errno which
	* tools/man2tcl.c:	are known to cause problems with recent
				glibc. [Bug 852369]

2003-12-09  Vince Darley  <vincentdarley@users.sourceforge.net>

	* win/tclWinFile.c: fix to NT file permissions code [Bug 855923]
	* tests/winFile.test: added tests for NT file permissions - patch
	and test scripts supplied by Benny.
	
	* tests/winFCmd.test: fixed one test for when not running in C:/
	
2003-12-02  Donal K. Fellows  <donal.k.fellows@man.ac.uk>

	* generic/tclBinary.c (DeleteScanNumberCache, ScanNumber): Made
	the numeric scan-value cache have proper references to the objects
	within it so strange patterns of writes won't cause references to
	freed objects. [Bug 851747]

2003-12-01  Miguel Sofer <msofer@users.sf.net>

	* doc/lset.n: fix typo [Bug 852224]

2003-11-24  Don Porter	<dgp@users.sourceforge.net>

	* generic/tclParse.c:	Corrected faulty check for trailing white
	space in {expand} parsing.  Thanks Andreas Leitgeb.  [Bug 848262].
	* tests/parse.test: 	New tests for the bug.

2003-11-24  Vince Darley  <vincentdarley@users.sourceforge.net>

	* generic/tclPathObj.c: fix to [Bug 845778] - Infinite recursion 
	on [cd] (Windows only bug), for which new tests have just been 
	added.
	
2003-11-21  Don Porter	<dgp@users.sourceforge.net>

	* tests/winFCmd.test (winFCmd-16.10,11): Merged new tests from
	core-8-4-branch.

2003-11-20  Miguel Sofer <msofer@users.sf.net>

	* generic/tclVar.c: fix flag bit collision between
	LOOKUP_FOR_UPVAR and TCL_PARSE_PART1 (deprecated) [Bug 835020] 
	
2003-11-19  Don Porter	<dgp@users.sourceforge.net>

	* tests/compile.test (compile-16.22.0):	Improved test for the
	recent fix for Bug 845412.

2003-11-19  Donal K. Fellows  <donal.k.fellows@man.ac.uk>

	* generic/tclCompile.c (TclCompileScript): Added a guard for the
	expansion code so that long non-expanding commands don't get
	expansion infrastructure inserted in them, especially when that
	infrastructure isn't initialised.  [Bug 845412]

2003-11-18  David Gravereaux <davygrvy@pobox.com>

	* contrib/djgpp/Makefile:		Changes from Victor Wagner
	* contrib/djgpp/langinfo.c (new):	<vitus@45.free.net> for better
	* contrib/djgpp/langinfo.h (new):	DJGPP support.
	* unix/tclUnixInit.c:			.
	* unix/tclUnixChan.c:			.
	* unix/tclUnixFCmd.c:			.

2003-11-17  Don Porter	<dgp@users.sourceforge.net>

	* tests/reg.test:  Added tests for [Bugs 230589, 504785, 505048, 840258]
	recently fixed by 2003-11-15 commit to regcomp.c by Pavel Goran.
	His notes on the fix: This bug results from an error in code that
	splits states into "progress" and "no-progress" ones. This error
	causes an interesting situation with the pre-collected single-linked
	list of states to be splitted: many items were added to the list, but 
	only several of them are accessible from the list beginning, 
	since the "tmp" member of struct state (which is used here to
	hold a pointer to the next list item) gets overwritten, which 
	results in a "looped" chain. As a result, not all of states are
	splitted, and one state is splitted two times, causing incorrect
	"no-progress" flag values.

2003-11-16  Donal K. Fellows  <donal.k.fellows@man.ac.uk>

	* generic/tclExecute.c (TclExecuteByteCode): Make sure that
	Tcl_AsyncInvoke is called regularly when processing bytecodes.
	* generic/tclTest.c (AsyncThreadProc, TestasyncCmd): Extended
	testing harness to send an asynchronous marking without relying on
	UNIX signals.
	* tests/async.test (async-4.*): Tests to check that async events
	are handled by the bytecode core. [Bug 746722]

2003-11-15  Donal K. Fellows  <donal.k.fellows@man.ac.uk>

	* generic/tclTest.c (TestHashSystemHashCmd): Removed 'const'
	modifier from hash type structure; it should be const and the hash
	code assumes it behaves like const, but that's not how the API is
	defined. Like this, we are following in the same footsteps as
	Tcl_RegisterObjType() which has the same conditions on its
	argument. Stops VC++5.2 warning.  [Bug 842511]

2003-11-14  Donal K. Fellows  <donal.k.fellows@man.ac.uk>

	* generic/tclHash.c (Tcl_DeleteHashTable,Tcl_HashStats,RebuildTable): 
	* generic/tclTest.c (TestHashSystemHashCmd): TIP#138 implementation, 
	* tests/misc.test:	plus a new chunk of stuff to test the hash
				functions more thoroughly in the test
				suite. [Patch 731356, modified] 

	* doc/Tcl.n: Updated Tcl version number and changebars.

2003-11-14  Don Porter	<dgp@users.sourceforge.net>

	* doc/ParseCmd.3:	Implementation of TIP 157.  Adds recognition
	* doc/Tcl.n:		of the new leading {expand} syntax on words.
	* generic/tcl.h:	Parses such words as the new Tcl_Token type
	* generic/tclBasic.c:	TCL_TOKEN_EXPAND_WORD.  Updated Tcl_EvalEx
	* generic/tclCompile.c: and the bytecode compiler/execution engine
	* generic/tclCompile.h:	to recognize the new token type.  New opcodes
	* generic/tclExecute.c:	INST_LIST_VERIFY and INST_INVOKE_EXP and a new
	* generic/tclParse.c:	operand type OPERAND_ULIST1 are defined.  Docs
	* generic/tclTest.c:	and tests are included.
	* tests/basic.test:
	* tests/compile.test:
	* tests/parse.test:

	* library/auto.tcl:	Replaced several [eval]s used to perform
	* library/package.tcl:	argument expansion with the new syntax.
	* library/safe.tcl:	In the test files lindex.test and lset.test,
	* tests/cmdInfo.test:	replaced use of [eval] to force direct
	* tests/encoding.test:	string evaluation with use of [testevalex]
	* tests/execute.test:	which more directly and robustly serves the
	* tests/fCmd.test:	same purpose.
	* tests/http.test:
	* tests/init.test:
	* tests/interp.test:
	* tests/io.test:
	* tests/ioUtil.test:
	* tests/iogt.test:
	* tests/lindex.test:
	* tests/lset.test:
	* tests/namespace-old.test:
	* tests/namespace.test:
	* tests/pkg.test:
	* tests/pkgMkIndex.test:
	* tests/proc.test:
	* tests/reg.test:
	* tests/trace.test:
	* tests/upvar.test:
	* tests/winConsole.test:
	* tests/winFCmd.test:

2003-11-12  Jeff Hobbs  <jeffh@ActiveState.com>

	* tests/cmdMZ.test (cmdMZ-1.4): change to nonPortable as more
	systems are using permissions caching, and this isn't really a Tcl
	controlled issue.

2003-11-11  Jeff Hobbs  <jeffh@ActiveState.com>

	* unix/configure:
	* unix/tcl.m4: improve AIX --enable-64bit handling
	remove -D__NO_STRING_INLINES -D__NO_MATH_INLINES from
	CFLAGS_OPTIMIZE on Linux.  Make default opt -O2 (was -O).

2003-11-11  David Gravereaux <davygrvy@pobox.com>

	* contrib/djgpp/Makefile:  Suggested changes from vitus@45.free.net
	(Victor Wagner)

	* unix/tclUnixPort.h:  added socklen_t typedef for DJGPP

2003-11-10  Don Porter	<dgp@users.sourceforge.net>

        * unix/tclUnixInit.c (TclpInitLibraryPath):     
        * win/tclWinInit.c (TclpInitLibraryPath):       Fix for [Bug 832657]
        that should not run afoul of startup constraints.

        * library/dde/pkgIndex.tcl:     Added safeguards so that registry
        * library/reg/pkgIndex.tcl:     and dde packages are not offered
        * win/tclWinDde.c:      on non-Windows platforms.  Bumped to
        * win/tclWinReg.c:      registry 1.1.3 and dde 1.3.
	* win/Makefile.in:
	* win/configure.in:
	* win/makefile.bc:
	* win/makefile.vc:

	* win/configure:	autoconf (2.57)

2003-11-10  Donal K. Fellows  <donal.k.fellows@man.ac.uk>

	* tests/cmdIL.test: Stopped cmdIL-5.5 from stomping over the test
	command, and updated the tests to use some tcltest2 features in
	relation to cleanup. [Bug 838384]

2003-11-10  Vince Darley  <vincentdarley@users.sourceforge.net>

	* generic/tclCmdAH.c:
	* tests/fCmd.test: fix to misleading error message in 'file link'
	[Bug 836208]
	
2003-11-07  Vince Darley  <vincentdarley@users.sourceforge.net>

	* generic/tclIOUtil.c: fix to compiler warning/error with
	some compilers [Bug 835918]
	
2003-11-07  Daniel Steffen  <das@users.sourceforge.net>

	* macosx/Makefile: optimized builds define NDEBUG to turn off
	ThreadAlloc range checking.

2003-11-05  Don Porter	<dgp@users.sourceforge.net>

	* tests/unixInit.test (unixInit-2.10):  New test to expose [Bug 832657]
	failure of TclpInitLibraryPath() to properly handle .. in the path
	of the executable.

2003-11-04  Daniel Steffen  <das@users.sourceforge.net>

	* macosx/Makefile: added 'test' target.

2003-11-03  Vince Darley  <vincentdarley@users.sourceforge.net>

	* generic/tclIOUtil.c
	* generic/tclInt.h: added comments and re-arranged code to
	clarify distinction between Tcl_LoadHandle, ClientData for
	'load'ed code, and point out limitations of the design 
	introduced with Tcl 8.4.
	
	* unix/tclUnixFile.c: fix to memory leak
	
	* generic/tclCmdIL.c: removed warning on Windows.
	
2003-11-01  Donal K. Fellows  <fellowsd@cs.man.ac.uk>

	* generic/tclCmdIL.c (Tcl_LrepeatObjCmd): Check for sensible list
	lengths and allow for soft failure of the memory subsystem in the
	[lconcat] command [Bug 829027].  Uses direct list creation to
	avoid extra copies when working near the limit of available
	memory.  Also reorganized to encourage optimizing compilers to
	optimize heavily.
	* generic/tclListObj.c (TclNewListObjDirect): New list constructor
	that does not copy the array of objects. Useful for creating
	potentially very large lists or where you are about to throw away
	the array argument which is being used in its entirety.

2003-10-28  Miguel Sofer <msofer@users.sf.net>

	* generic/tclExecute.c (NEXT_INST macros): replaced macro variable
	"result" by "resultHandling" to avoid confusion.

2003-10-23  Andreas Kupries  <andreask@activestate.com>

	* unix/tclUnixChan.c (Tcl_MakeFileChannel): Applied [Patch 813606]
	  fixing [Bug 813087]. Detection of sockets was off for Mac OS X
	  which implements pipes as local sockets. The new code ensures
	  that only IP sockets are detected as such.

	* win/tclWinSock.c (TcpWatchProc): Watch for FD_CLOSE too when
	  asked for writable events by the generic layer.
	  (SocketEventProc): Generate a writable event too when a close is
	  detected.

	  Together the changes fix [Bug 599468].

2003-10-23  Vince Darley  <vincentdarley@users.sourceforge.net>

	* tests/resource.test:
	* mac/tclMacResource.c: fix to resource freeing problem in 'resource'
	command reported by Bernard Desgraupes.
	
	* doc/FileSystem.3: updated documentation for 'glob' fix on 2003-10-13
	below

2003-10-22  Donal K. Fellows  <fellowsd@cs.man.ac.uk>

	* generic/tclCmdAH.c (Tcl_FileObjCmd): Changed FILE_ prefix to FCMD_
	to stop symbol/#def clashes on Cygwin/Mingw32 on NT. [Bug 822528]

2003-10-21   Daniel Steffen  <das@users.sourceforge.net>

	* tools/tcltk-man2html.tcl: fixed incorrect html generated for
	.IP/.TP lists, now use <DL><DT>...<DD>...<P><DT>...<DD>...</DL>
	instead of illegal  <DL><P><DT>...<DD>...<P><DT>...<DD>...</DL>.
	Added skipping of directives directly after .TP to avoid them
	being used as item descriptions, e.g. .TP\n.VS in clock.n.

2003-10-21  Andreas Kupries  <andreask@pliers.activestate.com>

	* win/tclWinPipe.c (BuildCommandLine): Applied the patch coming
	  with [Bug 805605] to the code, fixing the incorrect use of
	  ispace noted by Ronald Dauster <ronaldd@users.sourceforge.net>.

2003-10-20  Kevin B. Kenny  <kennykb@users.sourceforge.net>

	* doc/msgcat.n:
	* library/msgcat/msgcat.tcl (mclocale,mcload):
	* tools/tcl.wse.in:
	* unix/Makefile.in:     Implementation of TIP#156
	* win/makefile.bc:      adding a "root locale" to
	* win/Makefile.in:      the 'msgcat' package. Advanced
	* win/Makefile.vc:      msgcat version number to 1.4.
	
2003-10-15  Donal K. Fellows  <fellowsd@cs.man.ac.uk>

	* generic/tclCmdIL.c (SortInfo,etc): Reorganized so that SortInfo
	carries an array of integer indices instead of a Tcl list.  This
	nips shimmering problems in the bud and simplifies SelectObjFromSublist
	at the cost of making setup slightly more complex. [Bug 823768]

Changes to doc/FileSystem.3.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
'\"
'\" Copyright (c) 2001 Vincent Darley
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" RCS: @(#) $Id: FileSystem.3,v 1.32.4.3 2003/09/05 23:08:05 dgp Exp $
'\" 
.so man.macros
.TH Filesystem 3 8.4 Tcl "Tcl Library Procedures"
.BS
.SH NAME
Tcl_FSRegister, Tcl_FSUnregister, Tcl_FSData, Tcl_FSMountsChanged, Tcl_FSGetFileSystemForPath, Tcl_FSGetPathType, Tcl_FSCopyFile, Tcl_FSCopyDirectory, Tcl_FSCreateDirectory, Tcl_FSDeleteFile, Tcl_FSRemoveDirectory, Tcl_FSRenameFile, Tcl_FSListVolumes, Tcl_FSEvalFile, Tcl_FSLoadFile, Tcl_FSMatchInDirectory, Tcl_FSLink, Tcl_FSLstat, Tcl_FSUtime, Tcl_FSFileAttrsGet, Tcl_FSFileAttrsSet, Tcl_FSFileAttrStrings, Tcl_FSStat, Tcl_FSAccess, Tcl_FSOpenFileChannel, Tcl_FSGetCwd, Tcl_FSChdir, Tcl_FSPathSeparator, Tcl_FSJoinPath, Tcl_FSSplitPath, Tcl_FSEqualPaths, Tcl_FSGetNormalizedPath, Tcl_FSJoinToPath, Tcl_FSConvertToPathType, Tcl_FSGetInternalRep, Tcl_FSGetTranslatedPath, Tcl_FSGetTranslatedStringPath, Tcl_FSNewNativePath, Tcl_FSGetNativePath, Tcl_FSFileSystemInfo, Tcl_AllocStatBuf \- procedures to interact with any filesystem
.SH SYNOPSIS






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
'\"
'\" Copyright (c) 2001 Vincent Darley
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" RCS: @(#) $Id: FileSystem.3,v 1.32.4.4 2004/02/07 05:47:59 dgp Exp $
'\" 
.so man.macros
.TH Filesystem 3 8.4 Tcl "Tcl Library Procedures"
.BS
.SH NAME
Tcl_FSRegister, Tcl_FSUnregister, Tcl_FSData, Tcl_FSMountsChanged, Tcl_FSGetFileSystemForPath, Tcl_FSGetPathType, Tcl_FSCopyFile, Tcl_FSCopyDirectory, Tcl_FSCreateDirectory, Tcl_FSDeleteFile, Tcl_FSRemoveDirectory, Tcl_FSRenameFile, Tcl_FSListVolumes, Tcl_FSEvalFile, Tcl_FSLoadFile, Tcl_FSMatchInDirectory, Tcl_FSLink, Tcl_FSLstat, Tcl_FSUtime, Tcl_FSFileAttrsGet, Tcl_FSFileAttrsSet, Tcl_FSFileAttrStrings, Tcl_FSStat, Tcl_FSAccess, Tcl_FSOpenFileChannel, Tcl_FSGetCwd, Tcl_FSChdir, Tcl_FSPathSeparator, Tcl_FSJoinPath, Tcl_FSSplitPath, Tcl_FSEqualPaths, Tcl_FSGetNormalizedPath, Tcl_FSJoinToPath, Tcl_FSConvertToPathType, Tcl_FSGetInternalRep, Tcl_FSGetTranslatedPath, Tcl_FSGetTranslatedStringPath, Tcl_FSNewNativePath, Tcl_FSGetNativePath, Tcl_FSFileSystemInfo, Tcl_AllocStatBuf \- procedures to interact with any filesystem
.SH SYNOPSIS
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
rename operation.
.AP "CONST char" *encodingName in
The encoding of the data stored in the
file identified by \fBpathPtr\fR and to be evaluted.
.AP "CONST char" *pattern in
Only files or directories matching this pattern will be returned by
\fBTcl_FSMatchInDirectory\fR.
.AP GlobTypeData *types in
Only files or directories matching the type descriptions contained in
this structure will be returned by \fBTcl_FSMatchInDirectory\fR.  It
is very important that the 'directory' flag is properly handled.
This parameter may be NULL.
.AP Tcl_Interp *interp in
Interpreter to use either for results, evaluation, or reporting error 
messages.
.AP ClientData clientData in
The native description of the path object to create.
.AP Tcl_Obj *firstPtr in







|


|







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
rename operation.
.AP "CONST char" *encodingName in
The encoding of the data stored in the
file identified by \fBpathPtr\fR and to be evaluted.
.AP "CONST char" *pattern in
Only files or directories matching this pattern will be returned by
\fBTcl_FSMatchInDirectory\fR.
.AP Tcl_GlobTypeData *types in
Only files or directories matching the type descriptions contained in
this structure will be returned by \fBTcl_FSMatchInDirectory\fR.  It
is very important that the 'directory' and 'mount' flags are properly handled.
This parameter may be NULL.
.AP Tcl_Interp *interp in
Interpreter to use either for results, evaluation, or reporting error 
messages.
.AP ClientData clientData in
The native description of the path object to create.
.AP Tcl_Obj *firstPtr in
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
\fBTcl_FSPathSeparator\fR returns the separator character to be used for 
most specific element of the path specified by pathPtr (i.e. the last 
part of the path).
.PP
The separator is returned as a Tcl_Obj containing a string of length
1.  If the path is invalid, NULL is returned.
.PP
\fBTcl_FSJoinPath\fR takes the given Tcl_Obj, which should be a valid list,

and returns the path object given by considering the first 'elements'
elements as valid path segments.  If elements < 0, we use the entire
list.
.PP

Returns object with refCount of zero, containing the joined path.



.PP
\fBTcl_FSSplitPath\fR takes the given Tcl_Obj, which should be a valid path,
and returns a Tcl List object containing each segment of that path as
an element.
.PP
Returns list object with refCount of zero.  If the passed in lenPtr is
non-NULL, we use it to return the number of elements in the returned
list.
.PP
\fBTcl_FSEqualPaths\fR tests whether the two paths given represent the same
filesystem object
.PP
It returns 1 if the paths are equal, and 0 if they are different.  If 
either path is NULL, 0 is always returned.
.PP
\fBTcl_FSGetNormalizedPath\fR this important function attempts to extract
from the given Tcl_Obj a unique normalized path representation, whose
string value can be used as a unique identifier for the file.
.PP
It returns the normalized path object, with refCount of zero, or NULL 
if the path was invalid or could otherwise not be successfully
converted.  Extraction of absolute, normalized paths is very
efficient (because the filesystem operates on these representations
internally), although the result when the filesystem contains
numerous symbolic links may not be the most user-friendly

version of a path.


.PP
\fBTcl_FSJoinToPath\fR takes the given object, which should usually be a
valid path or NULL, and joins onto it the array of paths segments
given.
.PP

Returns object with refCount of zero, containing the joined path.



.PP
\fBTcl_FSConvertToPathType\fR tries to convert the given Tcl_Obj to a valid
Tcl path type, taking account of the fact that the cwd may have changed
even if this object is already supposedly of the correct type.
The filename may begin with "~" (to indicate current user's home
directory) or "~<user>" (to indicate any user's home directory).
.PP







|
>
|
|
<

>
|
>
>
>



















|
|
|
|
|
|
>
|
>
>





>
|
>
>
>







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
\fBTcl_FSPathSeparator\fR returns the separator character to be used for 
most specific element of the path specified by pathPtr (i.e. the last 
part of the path).
.PP
The separator is returned as a Tcl_Obj containing a string of length
1.  If the path is invalid, NULL is returned.
.PP
\fBTcl_FSJoinPath\fR takes the given Tcl_Obj, which should be a valid
list (which is allowed to have a refCount of zero), and returns the path
object given by considering the first 'elements' elements as valid path
segments.  If elements < 0, we use the entire list.

.PP
Returns object, typically with refCount of zero (but it could be shared
under some conditions) , containing the joined path.  The caller must
add a refCount to the object before using it.  In particular, the
returned object could be an element of the given list, so freeing the
list might free the object prematurely if no refCount has been taken.
.PP
\fBTcl_FSSplitPath\fR takes the given Tcl_Obj, which should be a valid path,
and returns a Tcl List object containing each segment of that path as
an element.
.PP
Returns list object with refCount of zero.  If the passed in lenPtr is
non-NULL, we use it to return the number of elements in the returned
list.
.PP
\fBTcl_FSEqualPaths\fR tests whether the two paths given represent the same
filesystem object
.PP
It returns 1 if the paths are equal, and 0 if they are different.  If 
either path is NULL, 0 is always returned.
.PP
\fBTcl_FSGetNormalizedPath\fR this important function attempts to extract
from the given Tcl_Obj a unique normalized path representation, whose
string value can be used as a unique identifier for the file.
.PP
It returns the normalized path object, owned by Tcl, or NULL if the path
was invalid or could otherwise not be successfully converted.
Extraction of absolute, normalized paths is very efficient (because the
filesystem operates on these representations internally), although the
result when the filesystem contains numerous symbolic links may not be
the most user-friendly version of a path.  The return value is owned by
Tcl and has a lifetime equivalent to that of the \fIpathPtr\fR passed in
(unless that is a relative path, in which case the normalized path
object may be freed any time the cwd changes) - the caller can of
course increment the refCount if it wishes to maintain a copy for longer.
.PP
\fBTcl_FSJoinToPath\fR takes the given object, which should usually be a
valid path or NULL, and joins onto it the array of paths segments
given.
.PP
Returns object, typically with refCount of zero (but it could be shared
under some conditions), containing the joined path.  The caller must
add a refCount to the object before using it.  If any of the objects
passed into this function (pathPtr or path elements) have a refCount
of zero, they will be freed when this function returns.
.PP
\fBTcl_FSConvertToPathType\fR tries to convert the given Tcl_Obj to a valid
Tcl path type, taking account of the fact that the cwd may have changed
even if this object is already supposedly of the correct type.
The filename may begin with "~" (to indicate current user's home
directory) or "~<user>" (to indicate any user's home directory).
.PP
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
Returns NULL or a valid internal path representation.  This internal
representation is cached, so that repeated calls to this function will
not require additional conversions.
.PP
\fBTcl_FSGetTranslatedPath\fR attempts to extract the translated path
from the given Tcl_Obj.  
.PP
If the translation succeeds (i.e. the object is a valid path), then it
is returned.  Otherwise NULL will be returned, and an error message may
be left in the interpreter.  A "translated" path is one which
contains no "~" or "~user" sequences (these have been expanded to
their current representation in the filesystem).  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.


Again, \fBTcl_FSGetNormalizedPath\fR or \fBTcl_GetNativePath\fR are
usually better functions to use for most purposes.
.PP
\fBTcl_FSNewNativePath\fR performs something like that reverse of the
usual obj->path->nativerep conversions.  If some code retrieves a path
in native form (from, e.g. readlink 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.
.PP
The resulting object is a pure 'path' object, which will only receive 
a Utf-8 string representation if that is required by some Tcl code.
.PP
\fBTcl_FSGetNativePath\fR is for use by the Win/Unix/MacOS native
filesystems, so that they can easily retrieve the native (char* or
TCHAR*) representation of a path.  This function is a convenience
wrapper around \fBTcl_FSGetInternalRep\fR, and assumes the native
representation is string-based.  It may be desirable in the future
to have non-string-based native representations (for example, on
MacOS, a representation using a fileSpec of FSRef structure would
probably be more efficient).  On Windows a full Unicode
representation would allow for paths of unlimited length.  Currently
the representation is simply a character string containing the
complete, absolute path in the native encoding.






.PP
The native representation is cached so that repeated calls to this
function will not require additional conversions.



.PP
\fBTcl_FSFileSystemInfo\fR returns a list of two elements.  The first
element is the name of the filesystem (e.g. "native" or "vfs" or "zip"
or "prowrap", perhaps), and the second is the particular type of the
given path within that filesystem (which is filesystem dependent).  The
second element may be empty if the filesystem does not provide a
further categorization of files.







|
|
|
|
|
>
|
|
|

|

>
>
|
|














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


|
>
>
>







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
Returns NULL or a valid internal path representation.  This internal
representation is cached, so that repeated calls to this function will
not require additional conversions.
.PP
\fBTcl_FSGetTranslatedPath\fR attempts to extract the translated path
from the given Tcl_Obj.  
.PP
If the translation succeeds (i.e. the object is a valid path), then it is
returned.  Otherwise NULL will be returned, and an error message may be
left in the interpreter.  A "translated" path is one which contains no
"~" or "~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 ckfree 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 that reverse of the
usual obj->path->nativerep conversions.  If some code retrieves a path
in native form (from, e.g. readlink 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.
.PP
The resulting object is a pure 'path' object, which will only receive 
a Utf-8 string representation if that is required by some Tcl code.
.PP
\fBTcl_FSGetNativePath\fR is for use by the Win/Unix/MacOS native
filesystems, so that they can easily retrieve the native (char* or
TCHAR*) representation of a path.  This function is a convenience
wrapper around \fBTcl_FSGetInternalRep\fR, and assumes the native
representation is string-based.  It may be desirable in the future to
have non-string-based native representations (for example, on MacOS, a
representation using a fileSpec of FSRef structure would probably be
more efficient).  On Windows a full Unicode representation would allow
for paths of unlimited length.  Currently the representation is simply a
character string which may contain either the relative path or a
complete, absolute normalized path in the native encoding (complex
conditions dictate which of these will be provided, so neither can be
relied upon, unless the path is known to be absolute).  If you need a
native path which must be absolute, then you should ask for the native
version of a normalized path.  If for some reason a non-absolute,
non-normalized version of the path is needed, that must be constructed
separately (e.g. using \fBTcl_FSGetTranslatedPath\fR).
.PP
The native representation is cached so that repeated calls to this
function will not require additional conversions.  The return value is
owned by Tcl and has a lifetime equivalent to that of the \fIpathPtr\fR
passed in (unless that is a relative path, in which case the native
representation may be freed any time the cwd changes).
.PP
\fBTcl_FSFileSystemInfo\fR returns a list of two elements.  The first
element is the name of the filesystem (e.g. "native" or "vfs" or "zip"
or "prowrap", perhaps), and the second is the particular type of the
given path within that filesystem (which is filesystem dependent).  The
second element may be empty if the filesystem does not provide a
further categorization of files.
1042
1043
1044
1045
1046
1047
1048













1049
1050
1051
1052
1053
1054
1055
rather results should be added to the \fIresult\fR object given
(which can be assumed to be a valid Tcl list).  The matches added
to \fIresult\fR should include any path prefix given in \fIpathPtr\fR 
(this usually means they will be absolute path specifications). 
Note that if no matches are found, that simply leads to an empty 
result --- errors are only signaled for actual file or filesystem
problems which may occur during the matching process.













.SH UTIMEPROC       
.PP
Function to process a \fBTcl_FSUtime()\fR call.  Required to allow setting
(not reading) of times with 'file mtime', 'file atime' and the
open-r/open-w/fcopy implementation of 'file copy'.
.PP
.CS







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







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
rather results should be added to the \fIresult\fR object given
(which can be assumed to be a valid Tcl list).  The matches added
to \fIresult\fR should include any path prefix given in \fIpathPtr\fR 
(this usually means they will be absolute path specifications). 
Note that if no matches are found, that simply leads to an empty 
result --- errors are only signaled for actual file or filesystem
problems which may occur during the matching process.
.PP
There are two specific cases which it is important to handle correctly,
both when \fItypes\fR is non-NULL. The two cases are when \fItypes->types
& TCL_GLOB_TYPE_DIR\fR or \fItypes->types & TCL_GLOB_TYPE_MOUNT\fR are
true (and in particular when the other flags are false).  In the first of
these cases, the function must list the contained directories.  Tcl uses
this to implement recursive globbing, so it is critical that filesystems
implement directory matching correctly.  In the second of these cases,
with \fITCL_GLOB_TYPE_MOUNT\fR, the filesystem must list the mount points
which lie within the given \fIpathPtr\fR (and in this case, \fIpathPtr\fR
need not lie within the same filesystem - different to all other cases in
which this function is called).  Support for this is critical if Tcl is
to have seamless transitions between from one filesystem to another.
.SH UTIMEPROC       
.PP
Function to process a \fBTcl_FSUtime()\fR call.  Required to allow setting
(not reading) of times with 'file mtime', 'file atime' and the
open-r/open-w/fcopy implementation of 'file copy'.
.PP
.CS
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321




1322
1323
1324
1325
1326
1327
1328
	Tcl_Interp * \fIinterp\fR, 
	Tcl_Obj *\fIpathPtr\fR, 
	Tcl_LoadHandle * \fIhandlePtr\fR,
	Tcl_FSUnloadFileProc * \fIunloadProcPtr\fR);
.CE
.PP
Returns a standard Tcl completion code.  If an error occurs, an error
message is left in the interp's result.  The function dynamically loads
a binary code file into memory.  On a successful
load, the \fIhandlePtr\fR should be filled with a token for 
the dynamically loaded file, and the \fIunloadProcPtr\fR should be
filled in with the address of a procedure.  The procedure will be
called with the given Tcl_LoadHandle as its only parameter when Tcl 
needs to unload the file.




.SH UNLOADFILEPROC	    
.PP
Function to unload a previously successfully loaded file.  If load was
implemented, then this should also be implemented, if there is any
cleanup action required.
.PP
.CS







|
|
|
<
|
|
|
>
>
>
>







1344
1345
1346
1347
1348
1349
1350
1351
1352
1353

1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
	Tcl_Interp * \fIinterp\fR, 
	Tcl_Obj *\fIpathPtr\fR, 
	Tcl_LoadHandle * \fIhandlePtr\fR,
	Tcl_FSUnloadFileProc * \fIunloadProcPtr\fR);
.CE
.PP
Returns a standard Tcl completion code.  If an error occurs, an error
message is left in the interp's result.  The function dynamically loads a
binary code file into memory.  On a successful load, the \fIhandlePtr\fR
should be filled with a token for the dynamically loaded file, and the

\fIunloadProcPtr\fR should be filled in with the address of a procedure.
The unload procedure will be called with the given Tcl_LoadHandle as its
only parameter when Tcl needs to unload the file.  For example, for the
native filesystem, the \fBTcl_LoadHandle\fR returned is currently a token
which can be used in the private \fBTclpFindSymbol\fR to access functions
in the new code.  Each filesystem is free to define the
\fBTcl_LoadHandle\fR as it requires.
.SH UNLOADFILEPROC	    
.PP
Function to unload a previously successfully loaded file.  If load was
implemented, then this should also be implemented, if there is any
cleanup action required.
.PP
.CS
Changes to doc/Hash.3.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'\"
'\" 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.
'\" 
'\" RCS: @(#) $Id: Hash.3,v 1.10.4.1 2003/08/07 21:35:58 dgp Exp $
'\" 
.so man.macros
.TH Tcl_Hash 3 "" Tcl "Tcl Library Procedures"
.BS
.SH NAME
Tcl_InitHashTable, Tcl_InitCustomHashTable, Tcl_InitObjHashTable, Tcl_DeleteHashTable, Tcl_CreateHashEntry, Tcl_DeleteHashEntry, Tcl_FindHashEntry, Tcl_GetHashValue, Tcl_SetHashValue, Tcl_GetHashKey, Tcl_FirstHashEntry, Tcl_NextHashEntry, Tcl_HashStats \- procedures to manage hash tables
.SH SYNOPSIS







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'\"
'\" 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.
'\" 
'\" RCS: @(#) $Id: Hash.3,v 1.10.4.2 2004/02/07 05:47:59 dgp Exp $
'\" 
.so man.macros
.TH Tcl_Hash 3 "" Tcl "Tcl Library Procedures"
.BS
.SH NAME
Tcl_InitHashTable, Tcl_InitCustomHashTable, Tcl_InitObjHashTable, Tcl_DeleteHashTable, Tcl_CreateHashEntry, Tcl_DeleteHashEntry, Tcl_FindHashEntry, Tcl_GetHashValue, Tcl_SetHashValue, Tcl_GetHashKey, Tcl_FirstHashEntry, Tcl_NextHashEntry, Tcl_HashStats \- procedures to manage hash tables
.SH SYNOPSIS
252
253
254
255
256
257
258











259
260
261
262
263
264
265
.PP
The \fIflags\fR member is one or more of the following values OR'ed together:
.IP \fBTCL_HASH_KEY_RANDOMIZE_HASH\fR 25
There are some things, pointers for example which don't hash well 
because they do not use the lower bits. If this flag is set then the
hash table will attempt to rectify this by randomising the bits and 
then using the upper N bits as the index into the table.











.PP
The \fIhashKeyProc\fR member contains the address of a function 
called to calculate a hash value for the key.
.CS
typedef unsigned int (Tcl_HashKeyProc) (
    Tcl_HashTable *\fItablePtr\fR,
    VOID *\fIkeyPtr\fR);







>
>
>
>
>
>
>
>
>
>
>







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
.PP
The \fIflags\fR member is one or more of the following values OR'ed together:
.IP \fBTCL_HASH_KEY_RANDOMIZE_HASH\fR 25
There are some things, pointers for example which don't hash well 
because they do not use the lower bits. If this flag is set then the
hash table will attempt to rectify this by randomising the bits and 
then using the upper N bits as the index into the table.
.VS 8.5 br
.IP \fBTCL_HASH_KEY_SYSTEM_HASH\fR 25
This flag forces Tcl to use the memory allocation 
procedures provided by the operating system when allocating
and freeing memory used to store the hash table data structures,
and not any of Tcl's own customized memory allocation routines.
This is important if the hash table is to be used in the
implementation of a custom set of allocation routines, or something
that a custom set of allocation routines might depend on, in
order to avoid any circular dependency.
.VE 8.5
.PP
The \fIhashKeyProc\fR member contains the address of a function 
called to calculate a hash value for the key.
.CS
typedef unsigned int (Tcl_HashKeyProc) (
    Tcl_HashTable *\fItablePtr\fR,
    VOID *\fIkeyPtr\fR);
Changes to doc/Panic.3.
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
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" RCS: @(#) $Id: Panic.3,v 1.3 2001/08/25 20:14:06 dgp Exp $
'\" 
.so man.macros
.TH Tcl_Panic 3 8.4 Tcl "Tcl Library Procedures"
.BS
'\"  Note:  do not modify the .SH NAME line immediately below!
.SH NAME
Tcl_Panic, Tcl_PanicVA, Tcl_SetPanicProc, panic, panicVA \- report fatal error and abort
.SH SYNOPSIS
.nf
\fB#include <tcl.h>\fR
.sp
void
\fBTcl_Panic\fR(\fIformat\fR, \fIarg\fR, \fIarg\fR, \fI...\fR)
.sp
void
\fBTcl_PanicVA\fR(\fIformat\fR, \fIargList\fR)
.sp
void
\fBTcl_SetPanicProc\fR(\fIpanicProc\fR)
.sp
void
\fBpanic\fR(\fIformat\fR, \fIarg\fR, \fIarg\fR, \fI...\fR)
.sp
void
\fBpanicVA\fR(\fIformat\fR, \fIargList\fR)
.sp
.SH ARGUMENTS
.AS Tcl_PanicProc *panicProc
.AP "CONST char*" format in
A printf-style format string.
.AP "" arg in
Arguments matching the format string.
.AP va_list argList in




|






|













<
<
<
<
<
<







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
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" RCS: @(#) $Id: Panic.3,v 1.3.14.1 2004/02/07 05:47:59 dgp Exp $
'\" 
.so man.macros
.TH Tcl_Panic 3 8.4 Tcl "Tcl Library Procedures"
.BS
'\"  Note:  do not modify the .SH NAME line immediately below!
.SH NAME
Tcl_Panic, Tcl_PanicVA, Tcl_SetPanicProc \- report fatal error and abort
.SH SYNOPSIS
.nf
\fB#include <tcl.h>\fR
.sp
void
\fBTcl_Panic\fR(\fIformat\fR, \fIarg\fR, \fIarg\fR, \fI...\fR)
.sp
void
\fBTcl_PanicVA\fR(\fIformat\fR, \fIargList\fR)
.sp
void
\fBTcl_SetPanicProc\fR(\fIpanicProc\fR)
.sp






.SH ARGUMENTS
.AS Tcl_PanicProc *panicProc
.AP "CONST char*" format in
A printf-style format string.
.AP "" arg in
Arguments matching the format string.
.AP va_list argList in
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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
\fBTcl_PanicVA\fR is the same as \fBTcl_Panic\fR except that instead of
taking a variable number of arguments it takes an argument list.  The
procedures \fBpanic\fR and \fBpanicVA\fR are synonyms (implemented as
macros) for \fBTcl_Panic\fR and \fBTcl_PanicVA\fR, respectively.  They
exist to support old code; new code should use direct calls to
\fBTcl_Panic\fR or \fBTcl_PanicVA\fR.

.SH "SEE ALSO"
abort(3), printf(3), exec(n), format(n)

.SH KEYWORDS
abort, fatal, error








|
<
<
<
<







84
85
86
87
88
89
90
91




92
93
94
95
96
97
98
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
\fBTcl_PanicVA\fR is the same as \fBTcl_Panic\fR except that instead of
taking a variable number of arguments it takes an argument list.





.SH "SEE ALSO"
abort(3), printf(3), exec(n), format(n)

.SH KEYWORDS
abort, fatal, error

Changes to doc/ParseCmd.3.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
'\"
'\" Copyright (c) 1997 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" RCS: @(#) $Id: ParseCmd.3,v 1.11 2003/03/19 20:07:17 dgp Exp $
'\" 
.so man.macros
.TH Tcl_ParseCommand 3 8.3 Tcl "Tcl Library Procedures"
.BS
.SH NAME
Tcl_ParseCommand, Tcl_ParseExpr, Tcl_ParseBraces, Tcl_ParseQuotedString, Tcl_ParseVarName, Tcl_ParseVar, Tcl_FreeParse, Tcl_EvalTokens, Tcl_EvalTokensStandard \- parse Tcl scripts and expressions
.SH SYNOPSIS






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
'\"
'\" Copyright (c) 1997 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" RCS: @(#) $Id: ParseCmd.3,v 1.11.2.1 2004/02/07 05:47:59 dgp Exp $
'\" 
.so man.macros
.TH Tcl_ParseCommand 3 8.3 Tcl "Tcl Library Procedures"
.BS
.SH NAME
Tcl_ParseCommand, Tcl_ParseExpr, Tcl_ParseBraces, Tcl_ParseQuotedString, Tcl_ParseVarName, Tcl_ParseVar, Tcl_FreeParse, Tcl_EvalTokens, Tcl_EvalTokensStandard \- parse Tcl scripts and expressions
.SH SYNOPSIS
282
283
284
285
286
287
288










289
290
291
292
293
294
295
number of sub-tokens that make up the word, including sub-tokens
of \fBTCL_TOKEN_VARIABLE\fR and \fBTCL_TOKEN_BS\fR tokens.
.TP
\fBTCL_TOKEN_SIMPLE_WORD\fR
This token has the same meaning as \fBTCL_TOKEN_WORD\fR, except that
the word is guaranteed to consist of a single \fBTCL_TOKEN_TEXT\fR
sub-token.  The \fInumComponents\fR field is always 1.










.TP
\fBTCL_TOKEN_TEXT\fR
The token describes a range of literal text that is part of a word.
The \fInumComponents\fR field is always 0.
.TP
\fBTCL_TOKEN_BS\fR
The token describes a backslash sequence such as \fB\en\fR or \fB\e0xa3\fR.







>
>
>
>
>
>
>
>
>
>







282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
number of sub-tokens that make up the word, including sub-tokens
of \fBTCL_TOKEN_VARIABLE\fR and \fBTCL_TOKEN_BS\fR tokens.
.TP
\fBTCL_TOKEN_SIMPLE_WORD\fR
This token has the same meaning as \fBTCL_TOKEN_WORD\fR, except that
the word is guaranteed to consist of a single \fBTCL_TOKEN_TEXT\fR
sub-token.  The \fInumComponents\fR field is always 1.
.VS 8.5
.TP
\fBTCL_TOKEN_EXPAND_WORD\fR
This token has the same meaning as \fBTCL_TOKEN_WORD\fR, except that
the command parser notes this word began with the expansion
prefix \fB{expand}\fR, indicating that after substitution,
the list value of this word should be expanded to form multiple
arguments in command evaluation.  This
token type can only be created by Tcl_ParseCommand.
.VE
.TP
\fBTCL_TOKEN_TEXT\fR
The token describes a range of literal text that is part of a word.
The \fInumComponents\fR field is always 0.
.TP
\fBTCL_TOKEN_BS\fR
The token describes a backslash sequence such as \fB\en\fR or \fB\e0xa3\fR.
371
372
373
374
375
376
377


378
379
380

381
382
383

384
385
386
387
388
389
390
\fIx\fR, \fIy\fR, and \fIz\fR.
The \fInumComponents\fR field for a \fBTCL_TOKEN_OPERATOR\fR token
is always 0.
.PP
After \fBTcl_ParseCommand\fR returns, the first token pointed to by
the \fItokenPtr\fR field of the
Tcl_Parse structure always has type \fBTCL_TOKEN_WORD\fR or


\fBTCL_TOKEN_SIMPLE_WORD\fR.  It is followed by the sub-tokens
that must be concatenated to produce the value of that word.
The next token is the \fBTCL_TOKEN_WORD\fR or \fBTCL_TOKEN_SIMPLE_WORD\fR

token for the second word, followed by sub-tokens for that
word, and so on until all \fInumWords\fR have been accounted
for.

.PP
After \fBTcl_ParseExpr\fR returns, the first token pointed to by
the \fItokenPtr\fR field of the
Tcl_Parse structure always has type \fBTCL_TOKEN_SUB_EXPR\fR.
It is followed by the sub-tokens that must be evaluated
to produce the value of the expression.
Only the token information in the Tcl_Parse structure







>
>
|


>
|


>







381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
\fIx\fR, \fIy\fR, and \fIz\fR.
The \fInumComponents\fR field for a \fBTCL_TOKEN_OPERATOR\fR token
is always 0.
.PP
After \fBTcl_ParseCommand\fR returns, the first token pointed to by
the \fItokenPtr\fR field of the
Tcl_Parse structure always has type \fBTCL_TOKEN_WORD\fR or
.VS 8.5
\fBTCL_TOKEN_SIMPLE_WORD\fR or \fBTCL_TOKEN_EXPAND_WORD\fR.  
It is followed by the sub-tokens
that must be concatenated to produce the value of that word.
The next token is the \fBTCL_TOKEN_WORD\fR or \fBTCL_TOKEN_SIMPLE_WORD\fR
of \fBTCL_TOKEN_EXPAND_WORD\fR token for the second word,
followed by sub-tokens for that
word, and so on until all \fInumWords\fR have been accounted
for.
.VE 8.5
.PP
After \fBTcl_ParseExpr\fR returns, the first token pointed to by
the \fItokenPtr\fR field of the
Tcl_Parse structure always has type \fBTCL_TOKEN_SUB_EXPR\fR.
It is followed by the sub-tokens that must be evaluated
to produce the value of the expression.
Only the token information in the Tcl_Parse structure
Changes to doc/Tcl.n.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
'\"
'\" 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.
'\" 
'\" RCS: @(#) $Id: Tcl.n,v 1.9 2003/02/01 19:48:23 kennykb Exp $
'\"
.so man.macros
.TH Tcl n "8.1" 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
17
18
'\"
'\" 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.
'\" 
'\" RCS: @(#) $Id: Tcl.n,v 1.9.4.1 2004/02/07 05:47:59 dgp Exp $
'\"
.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
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
the word is terminated by the next double-quote character.
If semi-colons, close brackets, or white space characters
(including newlines) appear between the quotes then they are treated
as ordinary characters and included in the word.
Command substitution, variable substitution, and backslash substitution
are performed on the characters between the quotes as described below.
The double-quotes are not retained as part of the word.










.IP "[5] \fBBraces.\fR"
If the first character of a word is an open brace (``{'') then

the word is terminated by the matching close brace (``}'').
Braces nest within the word: for each additional open
brace there must be an additional close brace (however,
if an open brace or close brace within the word is
quoted with a backslash then it is not counted in locating the
matching close brace).
No substitutions are performed on the characters between the
braces except for backslash-newline substitutions described
below, nor do semi-colons, newlines, close brackets,
or white space receive any special interpretation.
The word will consist of exactly the characters between the
outer braces, not including the braces themselves.
.IP "[6] \fBCommand substitution.\fR"
If a word contains an open bracket (``['') then Tcl performs
\fIcommand substitution\fR.
To do this it invokes the Tcl interpreter recursively to process
the characters following the open bracket as a Tcl script.
The script may contain any number of commands and must be terminated
by a close bracket (``]'').
The result of the script (i.e. the result of its last command) is
substituted into the word in place of the brackets and all of the
characters between them.
There may be any number of command substitutions in a single word.
Command substitution is not performed on words enclosed in braces.
.IP "[7] \fBVariable substitution.\fR"
If a word contains a dollar-sign (``$'') then Tcl performs \fIvariable
substitution\fR:  the dollar-sign and the following characters are
replaced in the word by the value of a variable.
Variable substitution may take any of the following forms:
.RS
.TP 15
\fB$\fIname\fR







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












|











|







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
the word is terminated by the next double-quote character.
If semi-colons, close brackets, or white space characters
(including newlines) appear between the quotes then they are treated
as ordinary characters and included in the word.
Command substitution, variable substitution, and backslash substitution
are performed on the characters between the quotes as described below.
The double-quotes are not retained as part of the word.
.VS 8.5 br
.IP "[5] \fBArgument expansion.\fR"
If a word starts with the string ``{expand}'' followed by a 
non-whitespace character, then the leading ``{expand}'' is removed
and the rest of the word is parsed and substituted as any other other 
word. After substitution, the word is parsed again without
substitutions, and its words are added to the command being
substituted. For instance, ``cmd a {expand}{b c} d {expand}{e f}'' is
equivalent to ``cmd a b c d e f''. 
.VE 8.5
.IP "[6] \fBBraces.\fR"
If the first character of a word is an open brace (``{'') and
rule [5] does not apply, then
the word is terminated by the matching close brace (``}'').
Braces nest within the word: for each additional open
brace there must be an additional close brace (however,
if an open brace or close brace within the word is
quoted with a backslash then it is not counted in locating the
matching close brace).
No substitutions are performed on the characters between the
braces except for backslash-newline substitutions described
below, nor do semi-colons, newlines, close brackets,
or white space receive any special interpretation.
The word will consist of exactly the characters between the
outer braces, not including the braces themselves.
.IP "[7] \fBCommand substitution.\fR"
If a word contains an open bracket (``['') then Tcl performs
\fIcommand substitution\fR.
To do this it invokes the Tcl interpreter recursively to process
the characters following the open bracket as a Tcl script.
The script may contain any number of commands and must be terminated
by a close bracket (``]'').
The result of the script (i.e. the result of its last command) is
substituted into the word in place of the brackets and all of the
characters between them.
There may be any number of command substitutions in a single word.
Command substitution is not performed on words enclosed in braces.
.IP "[8] \fBVariable substitution.\fR"
If a word contains a dollar-sign (``$'') then Tcl performs \fIvariable
substitution\fR:  the dollar-sign and the following characters are
replaced in the word by the value of a variable.
Variable substitution may take any of the following forms:
.RS
.TP 15
\fB$\fIname\fR
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
\fB${\fIname\fB}\fR
\fIName\fR is the name of a scalar variable.  It may contain any
characters whatsoever except for close braces.
.LP
There may be any number of variable substitutions in a single word.
Variable substitution is not performed on words enclosed in braces.
.RE
.IP "[8] \fBBackslash substitution.\fR"
If a backslash (``\e'') appears within a word then
\fIbackslash substitution\fR occurs.
In all cases but those described below the backslash is dropped and
the following character is treated as an ordinary
character and included in the word.
This allows characters such as double quotes, close brackets,
and dollar signs to be included in words without triggering







|







109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
\fB${\fIname\fB}\fR
\fIName\fR is the name of a scalar variable.  It may contain any
characters whatsoever except for close braces.
.LP
There may be any number of variable substitutions in a single word.
Variable substitution is not performed on words enclosed in braces.
.RE
.IP "[9] \fBBackslash substitution.\fR"
If a backslash (``\e'') appears within a word then
\fIbackslash substitution\fR occurs.
In all cases but those described below the backslash is dropped and
the following character is treated as an ordinary
character and included in the word.
This allows characters such as double quotes, close brackets,
and dollar signs to be included in words without triggering
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
is replaced in a separate pre-pass before the command is actually parsed.
This means that it will be replaced even when it occurs between braces,
and the resulting space will be treated as a word separator if it isn't
in braces or quotes.
.TP 7
\e\e
Backslash (``\e'').
.VS 8.1 br
.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.
.VE
.LP
Backslash substitution is not performed on words enclosed in braces,
except for backslash-newline as described above.
.RE
.IP "[9] \fBComments.\fR"
If a hash character (``#'') appears at a point where Tcl is
expecting the first character of the first word of a command,
then the hash character and the characters that follow it, up
through the next newline, are treated as a comment and ignored.
The comment character only has significance when it appears
at the beginning of a command.
.IP "[10] \fBOrder of substitution.\fR"
Each character is processed exactly once by the Tcl interpreter
as part of creating the words of a command.
For example, if variable substitution occurs then no further
substitutions are performed on the value of the variable;  the
value is inserted into the word verbatim.
If command substitution occurs then the nested command is
processed entirely by the recursive call to the Tcl interpreter;
no substitutions are performed before making the recursive
call and no additional substitutions are performed on the result
of the nested script.
.RS
.LP
Substitutions take place from left to right, and each substitution is
evaluated completely before attempting to evaluate the next.  Thus, a
sequence like
.CS
set y [set x 0][incr x][incr x]
.CE
will always set the variable \fIy\fR to the value, \fI012\fR.
.RE
.IP "[11] \fBSubstitution and word boundaries.\fR"
Substitutions do not affect the word boundaries of a command.

For example, during variable substitution the entire value of
the variable becomes part of a single word, even if the variable's
value contains spaces.







<




















<




|






|




















|
|
>



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
is replaced in a separate pre-pass before the command is actually parsed.
This means that it will be replaced even when it occurs between braces,
and the resulting space will be treated as a word separator if it isn't
in braces or quotes.
.TP 7
\e\e
Backslash (``\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.

.LP
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 (``#'') appears at a point where Tcl is
expecting the first character of the first word of a command,
then the hash character and the characters that follow it, up
through the next newline, are treated as a comment and ignored.
The comment character only has significance when it appears
at the beginning of a command.
.IP "[11] \fBOrder of substitution.\fR"
Each character is processed exactly once by the Tcl interpreter
as part of creating the words of a command.
For example, if variable substitution occurs then no further
substitutions are performed on the value of the variable;  the
value is inserted into the word verbatim.
If command substitution occurs then the nested command is
processed entirely by the recursive call to the Tcl interpreter;
no substitutions are performed before making the recursive
call and no additional substitutions are performed on the result
of the nested script.
.RS
.LP
Substitutions take place from left to right, and each substitution is
evaluated completely before attempting to evaluate the next.  Thus, a
sequence like
.CS
set y [set x 0][incr x][incr x]
.CE
will always set the variable \fIy\fR to the value, \fI012\fR.
.RE
.IP "[12] \fBSubstitution and word boundaries.\fR"
Substitutions do not affect the word boundaries of a command,
except for argument expansion as specified in rule [5].
For example, during variable substitution the entire value of
the variable becomes part of a single word, even if the variable's
value contains spaces.
Changes to doc/clock.n.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
'\"
'\" Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans.
'\" Copyright (c) 1995-1997 Sun Microsystems, Inc.
'\" Copyright (c) 1998-1999 Scriptics Corporation
'\" Copyright (c) 2002 ActiveState Corporation
'\"
'\" This documentation is derived from the time and date facilities of
'\" TclX, by Mark Diekhans and Karl Lehenbauer.
'\" 
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" RCS: @(#) $Id: clock.n,v 1.12 2003/04/12 19:08:54 kennykb Exp $
'\" 
.so man.macros
.TH clock n 8.4 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
clock \- Obtain and manipulate time












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
'\"
'\" Copyright (c) 1992-1995 Karl Lehenbauer and Mark Diekhans.
'\" Copyright (c) 1995-1997 Sun Microsystems, Inc.
'\" Copyright (c) 1998-1999 Scriptics Corporation
'\" Copyright (c) 2002 ActiveState Corporation
'\"
'\" This documentation is derived from the time and date facilities of
'\" TclX, by Mark Diekhans and Karl Lehenbauer.
'\" 
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" RCS: @(#) $Id: clock.n,v 1.12.2.1 2004/02/07 05:47:59 dgp Exp $
'\" 
.so man.macros
.TH clock n 8.4 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
clock \- Obtain and manipulate time
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
speed up the clock frequency slightly until it's back in synchronization.
For this reason, most Tcl programmers need never worry about such
phenomena as leap seconds.
.VE 8.5
.TP
\fBclock format \fIclockValue\fR ?\fB\-format \fIstring\fR? ?\fB\-gmt \fIboolean\fR?
Converts an integer time value, typically returned by
\fBclock seconds\fR, \fBclock scan\fR, or the \fBatime\fR, \fBmtime\fR,
or \fBctime\fR options of the \fBfile\fR command, to human-readable
form.  If the \fB\-format\fR argument is present the next argument is a
string that describes how the date and time are to be formatted.
Field descriptors consist of a \fB%\fR followed by a field
descriptor character.  All other characters are copied into the result.
Valid field descriptors are:
.RS
.IP \fB%%\fR







|
|







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
speed up the clock frequency slightly until it's back in synchronization.
For this reason, most Tcl programmers need never worry about such
phenomena as leap seconds.
.VE 8.5
.TP
\fBclock format \fIclockValue\fR ?\fB\-format \fIstring\fR? ?\fB\-gmt \fIboolean\fR?
Converts an integer time value, typically returned by
\fBclock seconds\fR, \fBclock scan\fR, or the \fBatime\fR or \fBmtime\fR
options of the \fBfile\fR command, to human-readable
form.  If the \fB\-format\fR argument is present the next argument is a
string that describes how the date and time are to be formatted.
Field descriptors consist of a \fB%\fR followed by a field
descriptor character.  All other characters are copied into the result.
Valid field descriptors are:
.RS
.IP \fB%%\fR
Changes to doc/file.n.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'\"
'\" 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.
'\" 
'\" RCS: @(#) $Id: file.n,v 1.24.2.1 2003/07/07 20:23:38 dgp Exp $
'\" 
.so man.macros
.TH file n 8.3 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
file \- Manipulate file names and attributes







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'\"
'\" 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.
'\" 
'\" RCS: @(#) $Id: file.n,v 1.24.2.2 2004/02/07 05:47:59 dgp Exp $
'\" 
.so man.macros
.TH file n 8.3 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
file \- Manipulate file names and attributes
99
100
101
102
103
104
105
106


107
108
109
110
111
112
113
114
115
116
117
.RS
The first form makes a copy of the file or directory \fIsource\fR under
the pathname \fItarget\fR. If \fItarget\fR is an existing directory,
then the second form is used.  The second form makes a copy inside
\fItargetDir\fR of each \fIsource\fR file listed.  If a directory is
specified as a \fIsource\fR, then the contents of the directory will be
recursively copied into \fItargetDir\fR. Existing files will not be
overwritten unless the \fB\-force\fR option is specified.  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 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.
.RE
.TP
\fBfile delete \fR?\fB\-force\fR? ?\fB\-\|\-\fR? \fIpathname\fR ?\fIpathname\fR ... ?







|
>
>



|







99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
.RS
The first form makes a copy of the file or directory \fIsource\fR under
the pathname \fItarget\fR. If \fItarget\fR is an existing directory,
then the second form is used.  The second form makes a copy inside
\fItargetDir\fR of each \fIsource\fR file listed.  If a directory is
specified as a \fIsource\fR, then the contents of the directory will be
recursively copied into \fItargetDir\fR. Existing files will not be
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.
.RE
.TP
\fBfile delete \fR?\fB\-force\fR? ?\fB\-\|\-\fR? \fIpathname\fR ?\fIpathname\fR ... ?
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
If only one argument is given, that argument is assumed to be
\fIlinkName\fR, and this command returns the value of the link given by
\fIlinkName\fR (i.e. the name of the file it points to).  If
\fIlinkName\fR isn't a link or its value cannot be read (as, for example,
seems to be the case with hard links, which look just like ordinary
files), then an error is returned.
.
If 2 arguments are given, then these are assumed to be \fIlinkName\fR and
\fItarget\fR. If \fIlinkName\fR already exists, or if \fItarget\fR
doesn't exist, an error will be returned.  Otherwise, Tcl creates a new
link called \fIlinkName\fR which points to the existing filesystem object

at \fItarget\fR, where the type of the link is platform-specific (on Unix
a symbolic link will be the default).  This is useful for the case where
the user wishes to create a link in a cross-platform way, and doesn't
care what type of link is created.
.
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 "-symbolic" and "-hard".
.






When creating links on filesystems that either do not support any links,
or do not support the specific type requested, an error message will be
returned.  In particular Windows 95, 98 and ME do not support any links
at present, but most Unix platforms support both symbolic and hard links
(the latter for files only), MacOS supports symbolic links and Windows
NT/2000/XP (on NTFS drives) support symbolic directory links and hard
file links.
.TP
\fBfile lstat \fIname varName\fR
.
Same as \fBstat\fR option (see below) except uses the \fIlstat\fR
kernel call instead of \fIstat\fR.  This means that if \fIname\fR
refers to a symbolic link the information returned in \fIvarName\fR
is for the link rather than the file it refers to.  On systems that







|
|

|
>
|
|
|
|






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







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
If only one argument is given, that argument is assumed to be
\fIlinkName\fR, and this command returns the value of the link given by
\fIlinkName\fR (i.e. the name of the file it points to).  If
\fIlinkName\fR isn't a link or its value cannot be read (as, for example,
seems to be the case with hard links, which look just like ordinary
files), then an error is returned.
.
If 2 arguments are given, then these are assumed to be \fIlinkName\fR
and \fItarget\fR. If \fIlinkName\fR already exists, or if \fItarget\fR
doesn't exist, an error will be returned.  Otherwise, Tcl creates a new
link called \fIlinkName\fR which points to the existing filesystem
object at \fItarget\fR (which is also the returned value), where the
type of the link is platform-specific (on Unix a symbolic link will be
the default).  This is useful for the case where the user wishes to
create a link in a cross-platform way, and doesn't care what type of
link is created.
.
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 "-symbolic" and "-hard".
.
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, "~user" paths are always expanded
to absolute form.  When creating links on filesystems that either do not
support any links, or do not support the specific type requested, an
error message will be returned.  In particular Windows 95, 98 and ME do
not support any links at present, but most Unix platforms support both
symbolic and hard links (the latter for files only), MacOS supports
symbolic links and Windows NT/2000/XP (on NTFS drives) support symbolic
directory links and hard file links.
.TP
\fBfile lstat \fIname varName\fR
.
Same as \fBstat\fR option (see below) except uses the \fIlstat\fR
kernel call instead of \fIstat\fR.  This means that if \fIname\fR
refers to a symbolic link the information returned in \fIvarName\fR
is for the link rather than the file it refers to.  On systems that
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
see the manual entry for \fBstat\fR for details on the meanings of the
values.  The \fBtype\fR element gives the type of the file in the same
form returned by the command \fBfile type\fR.  This command returns an
empty string.
.TP
\fBfile system \fIname\fR
.
Returns a list of two elements, the first of which is the name of the
filesystem to use for the file, and the second an arbitrary string
representing the filesystem-specific nature or type of the location
within that filesystem.  If a filesystem only supports one type of file,
the second element may be null.  For example the native files have a
first element 'native', and a second element which is a platform-specific
type name for the file's system (e.g. 'NTFS', 'FAT', etc), or possibly
the empty string if no further information is available or if this
is not implemented.  A generic virtual file system might return the
list 'vfs ftp' to represent a file on a remote ftp site mounted as a
virtual filesystem through an extension called 'vfs'.  If the file does
not belong to any filesystem, an error is generated.
.TP
\fBfile tail \fIname\fR
.
Returns all of the characters in the last filesystem component of
\fIname\fR.  Any trailing directory separator in \fIname\fR is ignored.







|
|
|
|
|
|
|
<
|
|







383
384
385
386
387
388
389
390
391
392
393
394
395
396

397
398
399
400
401
402
403
404
405
see the manual entry for \fBstat\fR for details on the meanings of the
values.  The \fBtype\fR element gives the type of the file in the same
form returned by the command \fBfile type\fR.  This command returns an
empty string.
.TP
\fBfile system \fIname\fR
.
Returns a list of one or two elements, the first of which is the name of
the filesystem to use for the file, and the second, if given, an
arbitrary string representing the filesystem-specific nature or type of
the location within that filesystem.  If a filesystem only supports one
type of file, the second element may not be supplied.  For example the
native files have a first element 'native', and a second element which
when given is a platform-specific type name for the file's system (e.g.

'NTFS', 'FAT', on Windows).  A generic virtual file system might return
the list 'vfs ftp' to represent a file on a remote ftp site mounted as a
virtual filesystem through an extension called 'vfs'.  If the file does
not belong to any filesystem, an error is generated.
.TP
\fBfile tail \fIname\fR
.
Returns all of the characters in the last filesystem component of
\fIname\fR.  Any trailing directory separator in \fIname\fR is ignored.
Changes to doc/filename.n.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
'\"
'\" Copyright (c) 1995-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.
'\" 
'\" RCS: @(#) $Id: filename.n,v 1.7.14.1 2003/10/16 02:28:01 dgp Exp $
'\" 
.so man.macros
.TH filename n 7.5 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
filename \- File name conventions supported by Tcl commands






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
'\"
'\" Copyright (c) 1995-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.
'\" 
'\" RCS: @(#) $Id: filename.n,v 1.7.14.2 2004/02/07 05:47:59 dgp Exp $
'\" 
.so man.macros
.TH filename n 7.5 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
filename \- File name conventions supported by Tcl commands
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

.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
\fBmac\fR
On Apple Macintosh systems, Tcl supports two forms of path names.  The
normal Mac style names use colons as path separators.  Paths may be
relative or absolute, and file names may contain any character other
than colon.  A leading colon causes the rest of the path to be
interpreted relative to the current directory.  If a path contains a
colon that is not at the beginning, then the path is interpreted as an
absolute path.  Sequences of two or more colons anywhere in the path
are used to construct relative paths where \fB::\fR refers to the
parent of the current directory, \fB:::\fR refers to the parent of the
parent, and so forth.
.RS
.PP
In addition to Macintosh style names, Tcl also supports a subset of
Unix-like names.  If a path contains no colons, then it is interpreted
like a Unix path.  Slash is used as the path separator.  The file name
\fB\&.\fR refers to the current directory, and \fB\&..\fR refers to the
parent of the current directory.  However, some names like \fB/\fR or







|
|
|
|
|
|
|
|
|
|







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

.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
\fBmac\fR
On Apple Macintosh Classic systems (i.e. with MacOS 9.x or older), Tcl
supports two forms of path names.  The normal Mac style names use colons
as path separators.  Paths may be relative or absolute, and file names
may contain any character other than colon.  A leading colon causes the
rest of the path to be interpreted relative to the current directory.
If a path contains a colon that is not at the beginning, then the path
is interpreted as an absolute path.  Sequences of two or more colons
anywhere in the path are used to construct relative paths where \fB::\fR
refers to the parent of the current directory, \fB:::\fR refers to the
parent of the parent, and so forth.
.RS
.PP
In addition to Macintosh style names, Tcl also supports a subset of
Unix-like names.  If a path contains no colons, then it is interpreted
like a Unix path.  Slash is used as the path separator.  The file name
\fB\&.\fR refers to the current directory, and \fB\&..\fR refers to the
parent of the current directory.  However, some names like \fB/\fR or
96
97
98
99
100
101
102
103
104
105
106
107
108
109

110
111
112
113
114
115
116
.TP 15
\fB\&../MyFile\fR
Relative path to a file named \fBMyFile\fR in the folder above the
current folder.
.RE
.TP
\fBunix\fR
On Unix 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.  Multiple
adjacent slash characters are interpreted as a single separator.
The following examples illustrate various forms of path names:

.RS
.TP 15
\fB/\fR
Absolute path to the root directory.
.TP 15
\fB/etc/passwd\fR
Absolute path to the file named \fBpasswd\fR in the directory







|
|
|
|
|
|
|
>







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
.TP 15
\fB\&../MyFile\fR
Relative path to a file named \fBMyFile\fR in the folder above the
current folder.
.RE
.TP
\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.
Multiple adjacent slash characters are interpreted as a single
separator.  The following examples illustrate various forms of path
names:
.RS
.TP 15
\fB/\fR
Absolute path to the root directory.
.TP 15
\fB/etc/passwd\fR
Absolute path to the file named \fBpasswd\fR in the directory
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
volume.  This is not a valid UNC path, so the assumption is that the
extra backslashes are superfluous.
.RE

.SH "TILDE SUBSTITUTION"
.PP
In addition to the file name rules described above, Tcl also supports
\fIcsh\fR-style tilde substitution.  If a file name starts with a
tilde, then the file name will be interpreted as if the first element
is replaced with the location of the home directory for the given
user.  If the tilde is followed immediately by a separator, then the
\fB$HOME\fR environment variable is substituted.  Otherwise the
characters between the tilde and the next separator are taken as a
user name, which is used to retrieve the user's home directory for
substitution.
.PP

The Macintosh and Windows platforms do not support tilde substitution
when a user name follows the tilde.  On these platforms, attempts to
use a tilde followed by a user name will generate an error that the
user does not exist when Tcl attempts to interpret that part of the
path or otherwise access the file.  The behaviour of these paths
when not trying to interpret them is the same as on Unix.  File
names that have a tilde without a user name will be correctly
substituted using the \fB$HOME\fR environment variable, just like 
for Unix.

.SH "PORTABILITY ISSUES"
.PP
Not all file systems are case sensitive, so scripts should avoid code
that depends on the case of characters in a file name.  In addition,
the character sets allowed on different devices may differ, so scripts
should choose file names that do not contain special characters like:







|
|
|
|
|
|
|
|

>
|
|
|
|
<
|
|
|
|







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
volume.  This is not a valid UNC path, so the assumption is that the
extra backslashes are superfluous.
.RE

.SH "TILDE SUBSTITUTION"
.PP
In addition to the file name rules described above, Tcl also supports
\fIcsh\fR-style tilde substitution.  If a file name starts with a tilde,
then the file name will be interpreted as if the first element is
replaced with the location of the home directory for the given user.  If
the tilde is followed immediately by a separator, then the \fB$HOME\fR
environment variable is substituted.  Otherwise the characters between
the tilde and the next separator are taken as a user name, which is used
to retrieve the user's home directory for substitution.  This works on
Unix, MacOS X and Windows (except very old releases).
.PP
The Classic Macintosh (OS 9 and older) platform and old Windows
platforms do not support tilde substitution when a user name follows the
tilde.  On these platforms, attempts to use a tilde followed by a user
name will generate an error that the user does not exist when Tcl
attempts to interpret that part of the path or otherwise access the

file.  The behaviour of these paths when not trying to interpret them is
the same as on Unix.  File names that have a tilde without a user name
will be correctly substituted using the \fB$HOME\fR environment
variable, just like for Unix.

.SH "PORTABILITY ISSUES"
.PP
Not all file systems are case sensitive, so scripts should avoid code
that depends on the case of characters in a file name.  In addition,
the character sets allowed on different devices may differ, so scripts
should choose file names that do not contain special characters like:
211
212
213
214
215
216
217
218



219
220
221
222
223
224
On Windows platforms there are file and path length restrictions. 
Complete paths or filenames longer than about 260 characters will lead
to errors in most file operations.
.PP
Another Windows peculiarity is that any number of trailing dots '.'  in
filenames are totally ignored, so, for example, attempts to create a
file or directory with a name "foo." will result in the creation of a
file/directory with name "foo".



.SH KEYWORDS
current directory, absolute file name, relative file name,
volume-relative file name, portability

.SH "SEE ALSO"
file(n), glob(n)







|
>
>
>






212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
On Windows platforms there are file and path length restrictions. 
Complete paths or filenames longer than about 260 characters will lead
to errors in most file operations.
.PP
Another Windows peculiarity is that any number of trailing dots '.'  in
filenames are totally ignored, so, for example, attempts to create a
file or directory with a name "foo." will result in the creation of a
file/directory with name "foo".  This fact is reflected in in the
results of 'file normalize'.  Furthermore, a file name consisting only
of dots '.........' or dots with trailing characters '.....abc' is
illegal.
.SH KEYWORDS
current directory, absolute file name, relative file name,
volume-relative file name, portability

.SH "SEE ALSO"
file(n), glob(n)
Changes to doc/glob.n.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'\"
'\" 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.
'\" 
'\" RCS: @(#) $Id: glob.n,v 1.12 2002/07/01 18:24:39 jenglish Exp $
'\" 
.so man.macros
.TH glob n 8.3 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
glob \- Return names of files that match patterns







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'\"
'\" 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.
'\" 
'\" RCS: @(#) $Id: glob.n,v 1.12.4.1 2004/02/07 05:47:59 dgp Exp $
'\" 
.so man.macros
.TH glob n 8.3 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
glob \- Return names of files that match patterns
145
146
147
148
149
150
151







152
153
154
155
156
157
158
.LP
The \fBglob\fR command differs from csh globbing in two ways.
First, it does not sort its result list (use the \fBlsort\fR
command if you want the list sorted).
Second, \fBglob\fR only returns the names of files that actually
exist;  in csh no check for existence is made unless a pattern
contains a ?, *, or [] construct.








.SH "PORTABILITY ISSUES"
.PP
Unlike other Tcl commands that will accept both network and native
style names (see the \fBfilename\fR manual entry for details on how
native and network names are specified), the \fBglob\fR command only
accepts native names.  







>
>
>
>
>
>
>







145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
.LP
The \fBglob\fR command differs from csh globbing in two ways.
First, it does not sort its result list (use the \fBlsort\fR
command if you want the list sorted).
Second, \fBglob\fR only returns the names of files that actually
exist;  in csh no check for existence is made unless a pattern
contains a ?, *, or [] construct.
.LP
When the \fBglob\fR command returns relative paths whose filenames
start with a tilde ``~'' (for example through \fBglob *\fR or 
\fBglob -tails\fR, the returned list will not quote the tilde with
``./''.  This means care must be taken if those names are later to
be used with \fBfile join\fR, to avoid them being interpreted as
absolute paths pointing to a given user's home directory.

.SH "PORTABILITY ISSUES"
.PP
Unlike other Tcl commands that will accept both network and native
style names (see the \fBfilename\fR manual entry for details on how
native and network names are specified), the \fBglob\fR command only
accepts native names.  
Added doc/lassign.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
48
49
50
51
52
53
54
55
'\"
'\" Copyright (c) 1992-1999 Karl Lehenbauer & Mark Diekhans
'\" Copyright (c) 2004 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: lassign.n,v 1.1.2.1 2004/02/07 05:47:59 dgp Exp $
'\" 
.so man.macros
.TH lassign n 8.5 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
lassign \- Assign list elements to variables
.SH SYNOPSIS
\fBlassign \fIlist varName \fR?\fIvarName ...\fR?
.BE

.SH DESCRIPTION
.PP
This command treats the value \fIlist\fR as a list and assigns
successive elements from that list to the variables given by the
\fIvarName\fR arguments in order.  If there are more variable names
than list elements, the remaining variables are set to the empty
string.  If there are more list elements than variables, a list of
unassigned elements is returned.
.SH EXAMPLES
An illustration of how multiple assignment works, and what happens
when there are either too few or too many elements.
.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
The \fBlassign\fR command has other uses.  It can be used to create
the analogue of the "shift" command in many shell languages like this:
.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
Changes to doc/lset.n.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
'\"
'\" Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" RCS: @(#) $Id: lset.n,v 1.6 2003/01/23 14:18:33 dkf Exp $
'\" 
.so man.macros
.TH lset n 8.4 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
lset \- Change an element in a list






|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
'\"
'\" Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" RCS: @(#) $Id: lset.n,v 1.6.4.1 2004/02/07 05:47:59 dgp Exp $
'\" 
.so man.macros
.TH lset n 8.4 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
lset \- Change an element in a list
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
.CS
lset varName {} newValue
.CE
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 \fIvarBane\fR variable as a Tcl list.
It addresses the \fIindex\fR'th element in it 
(0 refers to the first element of the list).
When interpreting the list, \fBlset\fR observes the same rules
concerning braces and quotes and backslashes as the Tcl command
interpreter; however, variable
substitution and command substitution do not occur.
The command constructs a new list in which the designated element is







|







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
.CS
lset varName {} newValue
.CE
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.
It addresses the \fIindex\fR'th element in it 
(0 refers to the first element of the list).
When interpreting the list, \fBlset\fR observes the same rules
concerning braces and quotes and backslashes as the Tcl command
interpreter; however, variable
substitution and command substitution do not occur.
The command constructs a new list in which the designated element is
Changes to doc/msgcat.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
'\"
'\" Copyright (c) 1998 Mark Harrison.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" SCCS: @(#) msgcat.n
'\" 
.so man.macros
.TH "msgcat" n 1.3 msgcat "Tcl Bundled Packages"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
msgcat \- Tcl message catalog
.SH SYNOPSIS
\fBpackage require Tcl 8.2\fR
.sp
\fBpackage require msgcat 1.3\fR
.sp
\fB::msgcat::mc \fIsrc-string\fR ?\fIarg arg ...\fR?
.sp
\fB::msgcat::mcmax ?\fIsrc-string src-string ...\fR?
.sp
\fB::msgcat::mclocale \fR?\fInewLocale\fR?
.sp









|







|







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
'\"
'\" Copyright (c) 1998 Mark Harrison.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" SCCS: @(#) msgcat.n
'\" 
.so man.macros
.TH "msgcat" n 1.4 msgcat "Tcl Bundled Packages"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
msgcat \- Tcl message catalog
.SH SYNOPSIS
\fBpackage require Tcl 8.2\fR
.sp
\fBpackage require msgcat 1.4\fR
.sp
\fB::msgcat::mc \fIsrc-string\fR ?\fIarg arg ...\fR?
.sp
\fB::msgcat::mcmax ?\fIsrc-string src-string ...\fR?
.sp
\fB::msgcat::mclocale \fR?\fInewLocale\fR?
.sp
90
91
92
93
94
95
96

97

98
99
100
101
102
103
104
Returns an ordered list of the locales preferred by
the user, based on the user's language specification.
The list is ordered from most specific to least
preference.  The list is derived from the current
locale set in msgcat by \fBmsgcat::mclocale\fR, and
cannot be set independently.  For example, if the
current locale is en_US_funky, then \fBmsgcat::mcpreferences\fR

returns {en_US_funky en_US en}.

.TP
\fB::msgcat::mcload \fIdirname\fR
Searches the specified directory for files that match
the language specifications returned by \fB::msgcat::mcpreferences\fR
(note that these are all lowercase), extended by the file
extension ``.msg''.  Each matching file is 
read in order, assuming a UTF-8 encoding.  The file contents are







>
|
>







90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
Returns an ordered list of the locales preferred by
the user, based on the user's language specification.
The list is ordered from most specific to least
preference.  The list is derived from the current
locale set in msgcat by \fBmsgcat::mclocale\fR, and
cannot be set independently.  For example, if the
current locale is en_US_funky, then \fBmsgcat::mcpreferences\fR
.VS 1.4
returns \fB{en_US_funky en_US en {}}\fR.
.VE
.TP
\fB::msgcat::mcload \fIdirname\fR
Searches the specified directory for files that match
the language specifications returned by \fB::msgcat::mcpreferences\fR
(note that these are all lowercase), extended by the file
extension ``.msg''.  Each matching file is 
read in order, assuming a UTF-8 encoding.  The file contents are
163
164
165
166
167
168
169

170


171
172
173
174
175
176
177
178
179
180
attempt to extract locale information from the
registry.  If all these attempts to discover an initial locale
from the user's environment fail, msgcat defaults to an initial
locale of ``C''.
.PP
When a locale is specified by the user, a ``best match'' search is
performed during string translation.  For example, if a user specifies

en_GB_Funky, the locales ``en_GB_Funky'', ``en_GB'', and ``en'' are


searched in order until a matching translation string is found.  If no
translation string is available, then \fB::msgcat::unknown\fR is
called.

.SH "NAMESPACES AND MESSAGE CATALOGS"
.PP
Strings stored in the message catalog are stored relative
to the namespace from which they were added.  This allows
multiple packages to use the same strings without fear
of collisions with other packages.  It also allows the







>
|
>
>
|
|
|







165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
attempt to extract locale information from the
registry.  If all these attempts to discover an initial locale
from the user's environment fail, msgcat defaults to an initial
locale of ``C''.
.PP
When a locale is specified by the user, a ``best match'' search is
performed during string translation.  For example, if a user specifies
.VS 1.4
en_GB_Funky, the locales ``en_GB_Funky'', ``en_GB'', ``en'' and ``''
(the empty string)
.VE
are searched in order until a matching translation
string is found.  If no translation string is available, then
\fB::msgcat::unknown\fR is called.

.SH "NAMESPACES AND MESSAGE CATALOGS"
.PP
Strings stored in the message catalog are stored relative
to the namespace from which they were added.  This allows
multiple packages to use the same strings without fear
of collisions with other packages.  It also allows the
232
233
234
235
236
237
238






239
240
241
242
243
244
245
.IP [2]
The message file name is a msgcat locale specifier (all lowercase)
followed by ``.msg''.  For example:
.CS
es.msg    -- spanish
en_gb.msg -- United Kingdom English
.CE






.IP [3]
The file contains a series of calls to \fBmcset\fR and
\fBmcmset\fR, setting the necessary translation strings
for the language, likely enclosed in a \fBnamespace eval\fR
so that all source strings are tied to the namespace of
the package. For example, a short \fBes.msg\fR might contain:
.CS







>
>
>
>
>
>







237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
.IP [2]
The message file name is a msgcat locale specifier (all lowercase)
followed by ``.msg''.  For example:
.CS
es.msg    -- spanish
en_gb.msg -- United Kingdom English
.CE
.VS
\fIException:\fR The message file for the root locale ``'' is
called \fBROOT.msg\fR.  This exception is made so as not to
cause peculiar behavior, such as marking the message file as
``hidden'' on Unix file systems.
.VE
.IP [3]
The file contains a series of calls to \fBmcset\fR and
\fBmcmset\fR, setting the necessary translation strings
for the language, likely enclosed in a \fBnamespace eval\fR
so that all source strings are tied to the namespace of
the package. For example, a short \fBes.msg\fR might contain:
.CS
Changes to doc/switch.n.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'\"
'\" Copyright (c) 1993 The Regents of the University of California.
'\" Copyright (c) 1994-1997 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" RCS: @(#) $Id: switch.n,v 1.5 2000/09/07 14:27:51 poenitz Exp $
'\" 
.so man.macros
.TH switch n 7.0 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
switch \- Evaluate one of several scripts, depending on a given value







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'\"
'\" Copyright (c) 1993 The Regents of the University of California.
'\" Copyright (c) 1994-1997 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" RCS: @(#) $Id: switch.n,v 1.5.20.1 2004/02/07 05:47:59 dgp Exp $
'\" 
.so man.macros
.TH switch n 7.0 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
switch \- Evaluate one of several scripts, depending on a given value
44
45
46
47
48
49
50































51
52
53
54
55
56
57
When matching \fIstring\fR to the patterns, use glob-style matching
(i.e. the same as implemented by the \fBstring match\fR command).
.TP 10
\fB\-regexp\fR
When matching \fIstring\fR to the patterns, use regular
expression matching
(as described in the \fBre_syntax\fR reference page).































.TP 10
\fB\-\|\-\fR
Marks the end of options.  The argument following this one will
be treated as \fIstring\fR even if it starts with a \fB\-\fR.
.PP
Two syntaxes are provided for the \fIpattern\fR and \fIbody\fR arguments.
The first uses a separate argument for each of the patterns and commands;







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







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
When matching \fIstring\fR to the patterns, use glob-style matching
(i.e. the same as implemented by the \fBstring match\fR command).
.TP 10
\fB\-regexp\fR
When matching \fIstring\fR to the patterns, use regular
expression matching
(as described in the \fBre_syntax\fR reference page).
'\" Options defined by TIP#75
.VS 8.5
.TP 10
\fB\-matchvar\fR \fIvarName\fR
This option (only legal when \fB\-regexp\fR is also specified)
specifies the name of a variable into which the list of matches
found by the regular expression engine will be written.  The first
element of the list written will be the overall substring of the input
string (i.e. the \fIstring\fR argument to \fBswitch\fR) matched, the
second element of the list will be the substring matched by the first
capturing parenthesis in the regular expression that matched, and so
on.  When a \fBdefault\fR branch is taken, the variable will have the
empty list written to it.  This option may be specified at the same
time as the \fB\-indexvar\fR option.
.TP 10
\fB\-indexvar\fR \fIvarName\fR
This option (only legal when \fB\-regexp\fR is also specified)
specifies the name of a variable into which the list of indices
referring to matching substrings
found by the regular expression engine will be written.  The first
element of the list written will be a two-element list specifying the
index of the start and index of the first character after the end of
the overall substring of the input
string (i.e. the \fIstring\fR argument to \fBswitch\fR) matched, in a
similar way to the \fB\-indices\fR option to the \fBregexp\fR can
obtain.  Similarly, the second element of the list refers to the first
capturing parenthesis in the regular expression that matched, and so
on.  When a \fBdefault\fR branch is taken, the variable will have the
empty list written to it.  This option may be specified at the same
time as the \fB\-matchvar\fR option.
.VE 8.5
.TP 10
\fB\-\|\-\fR
Marks the end of options.  The argument following this one will
be treated as \fIstring\fR even if it starts with a \fB\-\fR.
.PP
Two syntaxes are provided for the \fIpattern\fR and \fIbody\fR arguments.
The first uses a separate argument for each of the patterns and commands;
Changes to doc/tclvars.n.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'\"
'\" Copyright (c) 1993 The Regents of the University of California.
'\" Copyright (c) 1994-1997 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" RCS: @(#) $Id: tclvars.n,v 1.13 2002/07/01 18:24:39 jenglish Exp $
'\" 
.so man.macros
.TH tclvars n 8.0 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
tclvars \- Variables used by Tcl







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
'\"
'\" Copyright (c) 1993 The Regents of the University of California.
'\" Copyright (c) 1994-1997 Sun Microsystems, Inc.
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\" 
'\" RCS: @(#) $Id: tclvars.n,v 1.13.4.1 2004/02/07 05:47:59 dgp Exp $
'\" 
.so man.macros
.TH tclvars n 8.0 Tcl "Tcl Built-In Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
tclvars \- Variables used by Tcl
253
254
255
256
257
258
259
260
261
262
263

264
265
266
267
268
269
270
.TP
\fBbyteOrder\fR
The native byte order of this machine: either \fBlittleEndian\fR or
\fBbigEndian\fR. 
.VE
.TP
\fBdebug\fR
If this variable exists, then the interpreter
was compiled with debugging symbols enabled.  This variable will only
exist on Windows so extension writers can specify which package to load
depending on the C run-time library that is loaded.

.TP
\fBmachine\fR
The instruction set executed by this machine, such as
\fBintel\fR, \fBPPC\fR, \fB68k\fR, or \fBsun4m\fR.  On UNIX machines, this
is the value returned by \fBuname -m\fR.
.TP
\fBos\fR 







|
|
|
|
>







253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
.TP
\fBbyteOrder\fR
The native byte order of this machine: either \fBlittleEndian\fR or
\fBbigEndian\fR. 
.VE
.TP
\fBdebug\fR
If this variable exists, then the interpreter was compiled with and linked
to a debug enabled C run-time.  This variable will only exist on Windows,
so extension writers can specify which package to load depending on the
C run-time library that is in use.  This is not an indication that this core
contains symbols.
.TP
\fBmachine\fR
The instruction set executed by this machine, such as
\fBintel\fR, \fBPPC\fR, \fB68k\fR, or \fBsun4m\fR.  On UNIX machines, this
is the value returned by \fBuname -m\fR.
.TP
\fBos\fR 
Changes to generic/regcomp.c.
549
550
551
552
553
554
555



556
557

558
559
560
561
562
563
564
	slist = NULL;
	for (a = pre->outs; a != NULL; a = a->outchain) {
		s = a->to;
		for (b = s->ins; b != NULL; b = b->inchain)
			if (b->from != pre)
				break;
		if (b != NULL) {		/* must be split */



			s->tmp = slist;
			slist = s;

		}
	}

	/* do the splits */
	for (s = slist; s != NULL; s = s2) {
		s2 = newstate(nfa);
		copyouts(nfa, s, s2);







>
>
>
|
|
>







549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
	slist = NULL;
	for (a = pre->outs; a != NULL; a = a->outchain) {
		s = a->to;
		for (b = s->ins; b != NULL; b = b->inchain)
			if (b->from != pre)
				break;
		if (b != NULL) {		/* must be split */
			if (s->tmp == NULL) {  /* if not already in the list */
			                       /* (fixes bugs 505048, 230589, */
			                       /* 840258, 504785) */
				s->tmp = slist;
				slist = s;
			}
		}
	}

	/* do the splits */
	for (s = slist; s != NULL; s = s2) {
		s2 = newstate(nfa);
		copyouts(nfa, s, s2);
Changes to generic/tcl.decls.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# tcl.decls --
#
#	This file contains the declarations for all supported public
#	functions that are exported by the Tcl library via the stubs table.
#	This file is used to generate the tclDecls.h, tclPlatDecls.h,
#	tclStub.c, and tclPlatStub.c files.
#	
#
# Copyright (c) 1998-1999 by Scriptics Corporation.
# Copyright (c) 2001, 2002 by Kevin B. Kenny.  All rights reserved.
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# RCS: @(#) $Id: tcl.decls,v 1.97.2.4 2003/10/16 02:28:01 dgp Exp $

library tcl

# Define the tcl interface with several sub interfaces:
#     tclPlat	 - platform specific public
#     tclInt	 - generic private
#     tclPlatInt - platform specific private













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# tcl.decls --
#
#	This file contains the declarations for all supported public
#	functions that are exported by the Tcl library via the stubs table.
#	This file is used to generate the tclDecls.h, tclPlatDecls.h,
#	tclStub.c, and tclPlatStub.c files.
#	
#
# Copyright (c) 1998-1999 by Scriptics Corporation.
# Copyright (c) 2001, 2002 by Kevin B. Kenny.  All rights reserved.
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# RCS: @(#) $Id: tcl.decls,v 1.97.2.5 2004/02/07 05:47:59 dgp Exp $

library tcl

# Define the tcl interface with several sub interfaces:
#     tclPlat	 - platform specific public
#     tclInt	 - generic private
#     tclPlatInt - platform specific private
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
declare 461 generic {
    Tcl_Obj* Tcl_FSSplitPath(Tcl_Obj* pathPtr, int *lenPtr)
}
declare 462 generic {
    int Tcl_FSEqualPaths(Tcl_Obj* firstPtr, Tcl_Obj* secondPtr)
}
declare 463 generic {
    Tcl_Obj* Tcl_FSGetNormalizedPath(Tcl_Interp *interp, Tcl_Obj* pathObjPtr)
}
declare 464 generic {
    Tcl_Obj* Tcl_FSJoinToPath(Tcl_Obj *basePtr, int objc,
	    Tcl_Obj *CONST objv[])
}
declare 465 generic {
    ClientData Tcl_FSGetInternalRep(Tcl_Obj* pathObjPtr,
	    Tcl_Filesystem *fsPtr)
}
declare 466 generic {
    Tcl_Obj* Tcl_FSGetTranslatedPath(Tcl_Interp *interp, Tcl_Obj* pathPtr)
}
declare 467 generic {
    int Tcl_FSEvalFile(Tcl_Interp *interp, Tcl_Obj *fileName)
}
declare 468 generic {
    Tcl_Obj* Tcl_FSNewNativePath(Tcl_Filesystem* fromFilesystem,
	    ClientData clientData)
}
declare 469 generic {
    CONST char* Tcl_FSGetNativePath(Tcl_Obj* pathObjPtr)
}
declare 470 generic {
    Tcl_Obj* Tcl_FSFileSystemInfo(Tcl_Obj* pathObjPtr)
}
declare 471 generic {
    Tcl_Obj* Tcl_FSPathSeparator(Tcl_Obj* pathObjPtr)
}
declare 472 generic {
    Tcl_Obj* Tcl_FSListVolumes(void)
}
declare 473 generic {
    int Tcl_FSRegister(ClientData clientData, Tcl_Filesystem *fsPtr)
}
declare 474 generic {
    int Tcl_FSUnregister(Tcl_Filesystem *fsPtr)
}
declare 475 generic {
    ClientData Tcl_FSData(Tcl_Filesystem *fsPtr)
}
declare 476 generic {
    CONST char* Tcl_FSGetTranslatedStringPath(Tcl_Interp *interp,
	    Tcl_Obj* pathPtr)
}
declare 477 generic {
    Tcl_Filesystem* Tcl_FSGetFileSystemForPath(Tcl_Obj* pathObjPtr)
}
declare 478 generic {
    Tcl_PathType Tcl_FSGetPathType(Tcl_Obj *pathObjPtr)
}
# New function due to TIP#49
declare 479 generic {
    int Tcl_OutputBuffered(Tcl_Channel chan)
}
declare 480 generic {
    void Tcl_FSMountsChanged(Tcl_Filesystem *fsPtr)







|


|



|













|


|


|


















|


|







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
declare 461 generic {
    Tcl_Obj* Tcl_FSSplitPath(Tcl_Obj* pathPtr, int *lenPtr)
}
declare 462 generic {
    int Tcl_FSEqualPaths(Tcl_Obj* firstPtr, Tcl_Obj* secondPtr)
}
declare 463 generic {
    Tcl_Obj* Tcl_FSGetNormalizedPath(Tcl_Interp *interp, Tcl_Obj* pathPtr)
}
declare 464 generic {
    Tcl_Obj* Tcl_FSJoinToPath(Tcl_Obj *pathPtr, int objc,
	    Tcl_Obj *CONST objv[])
}
declare 465 generic {
    ClientData Tcl_FSGetInternalRep(Tcl_Obj* pathPtr,
	    Tcl_Filesystem *fsPtr)
}
declare 466 generic {
    Tcl_Obj* Tcl_FSGetTranslatedPath(Tcl_Interp *interp, Tcl_Obj* pathPtr)
}
declare 467 generic {
    int Tcl_FSEvalFile(Tcl_Interp *interp, Tcl_Obj *fileName)
}
declare 468 generic {
    Tcl_Obj* Tcl_FSNewNativePath(Tcl_Filesystem* fromFilesystem,
	    ClientData clientData)
}
declare 469 generic {
    CONST char* Tcl_FSGetNativePath(Tcl_Obj* pathPtr)
}
declare 470 generic {
    Tcl_Obj* Tcl_FSFileSystemInfo(Tcl_Obj* pathPtr)
}
declare 471 generic {
    Tcl_Obj* Tcl_FSPathSeparator(Tcl_Obj* pathPtr)
}
declare 472 generic {
    Tcl_Obj* Tcl_FSListVolumes(void)
}
declare 473 generic {
    int Tcl_FSRegister(ClientData clientData, Tcl_Filesystem *fsPtr)
}
declare 474 generic {
    int Tcl_FSUnregister(Tcl_Filesystem *fsPtr)
}
declare 475 generic {
    ClientData Tcl_FSData(Tcl_Filesystem *fsPtr)
}
declare 476 generic {
    CONST char* Tcl_FSGetTranslatedStringPath(Tcl_Interp *interp,
	    Tcl_Obj* pathPtr)
}
declare 477 generic {
    Tcl_Filesystem* Tcl_FSGetFileSystemForPath(Tcl_Obj* pathPtr)
}
declare 478 generic {
    Tcl_PathType Tcl_FSGetPathType(Tcl_Obj *pathPtr)
}
# New function due to TIP#49
declare 479 generic {
    int Tcl_OutputBuffered(Tcl_Channel chan)
}
declare 480 generic {
    void Tcl_FSMountsChanged(Tcl_Filesystem *fsPtr)
Changes to generic/tcl.h.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 * Copyright (c) 1994-1998 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 by Scriptics Corporation.
 * Copyright (c) 2002 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tcl.h,v 1.157.2.5 2003/10/16 02:28:01 dgp Exp $
 */

#ifndef _TCL
#define _TCL

/*
 * For C++ compilers, use extern "C"







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 * Copyright (c) 1994-1998 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 by Scriptics Corporation.
 * Copyright (c) 2002 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tcl.h,v 1.157.2.6 2004/02/07 05:48:00 dgp Exp $
 */

#ifndef _TCL
#define _TCL

/*
 * For C++ compilers, use extern "C"
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
 * When version numbers change here, must also go into the following files
 * and update the version numbers:
 *
 * library/init.tcl	(only if Major.minor changes, not patchlevel) 1 LOC
 * unix/configure.in	(2 LOC Major, 2 LOC minor, 1 LOC patch)
 * win/configure.in	(as above)
 * win/tcl.m4		(not patchlevel)
 * win/makefile.vc	(not patchlevel) 2 LOC
 * win/makefile.bc	(not patchlevel) 2 LOC
 * README		(sections 0 and 2)
 * mac/README		(2 LOC, not patchlevel)
 * macosx/Tcl.pbproj/project.pbxproj (not patchlevel) 2 LOC
 * win/README.binary	(sections 0-4)
 * win/README		(not patchlevel) (sections 0 and 2)
 * unix/tcl.spec	(2 LOC Major/Minor, 1 LOC patch)







<







39
40
41
42
43
44
45

46
47
48
49
50
51
52
 * When version numbers change here, must also go into the following files
 * and update the version numbers:
 *
 * library/init.tcl	(only if Major.minor changes, not patchlevel) 1 LOC
 * unix/configure.in	(2 LOC Major, 2 LOC minor, 1 LOC patch)
 * win/configure.in	(as above)
 * win/tcl.m4		(not patchlevel)

 * win/makefile.bc	(not patchlevel) 2 LOC
 * README		(sections 0 and 2)
 * mac/README		(2 LOC, not patchlevel)
 * macosx/Tcl.pbproj/project.pbxproj (not patchlevel) 2 LOC
 * win/README.binary	(sections 0-4)
 * win/README		(not patchlevel) (sections 0 and 2)
 * unix/tcl.spec	(2 LOC Major/Minor, 1 LOC patch)
1165
1166
1167
1168
1169
1170
1171




1172
1173

1174
1175
1176
1177
1178
1179
1180
 * TCL_HASH_KEY_RANDOMIZE_HASH:
 *				There are some things, pointers for example
 *				which don't hash well because they do not use
 *				the lower bits. If this flag is set then the
 *				hash table will attempt to rectify this by
 *				randomising the bits and then using the upper
 *				N bits as the index into the table.




 */
#define TCL_HASH_KEY_RANDOMIZE_HASH 0x1


/*
 * Structure definition for the methods associated with a hash table
 * key type.
 */
#define TCL_HASH_KEY_TYPE_VERSION 1
struct Tcl_HashKeyType {







>
>
>
>


>







1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
 * TCL_HASH_KEY_RANDOMIZE_HASH:
 *				There are some things, pointers for example
 *				which don't hash well because they do not use
 *				the lower bits. If this flag is set then the
 *				hash table will attempt to rectify this by
 *				randomising the bits and then using the upper
 *				N bits as the index into the table.
 * TCL_HASH_KEY_SYSTEM_HASH:
 *				If this flag is set then all memory internally
 *                              allocated for the hash table that is not for an
 *                              entry will use the system heap.
 */
#define TCL_HASH_KEY_RANDOMIZE_HASH 0x1
#define TCL_HASH_KEY_SYSTEM_HASH    0x2

/*
 * Structure definition for the methods associated with a hash table
 * key type.
 */
#define TCL_HASH_KEY_TYPE_VERSION 1
struct Tcl_HashKeyType {
2074
2075
2076
2077
2078
2079
2080

2081
2082
2083
2084
2085
2086
2087
#define TCL_TOKEN_SIMPLE_WORD	2
#define TCL_TOKEN_TEXT		4
#define TCL_TOKEN_BS		8
#define TCL_TOKEN_COMMAND	16
#define TCL_TOKEN_VARIABLE	32
#define TCL_TOKEN_SUB_EXPR	64
#define TCL_TOKEN_OPERATOR	128


/*
 * Parsing error types.  On any parsing error, one of these values
 * will be stored in the error field of the Tcl_Parse structure
 * defined below.
 */
#define TCL_PARSE_SUCCESS		0







>







2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
#define TCL_TOKEN_SIMPLE_WORD	2
#define TCL_TOKEN_TEXT		4
#define TCL_TOKEN_BS		8
#define TCL_TOKEN_COMMAND	16
#define TCL_TOKEN_VARIABLE	32
#define TCL_TOKEN_SUB_EXPR	64
#define TCL_TOKEN_OPERATOR	128
#define TCL_TOKEN_EXPAND_WORD	256

/*
 * Parsing error types.  On any parsing error, one of these values
 * will be stored in the error field of the Tcl_Parse structure
 * defined below.
 */
#define TCL_PARSE_SUCCESS		0
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

typedef struct Tcl_Config {
    CONST char* key;   /* Configuration key to register. ASCII encoded, thus UTF-8 */
    CONST char* value; /* The value associated with the key. System encoding */
} Tcl_Config;




/*
 * Deprecated Tcl procedures:
 */
#ifndef TCL_NO_DEPRECATED
#   define Tcl_EvalObj(interp,objPtr) \
	Tcl_EvalObjEx((interp),(objPtr),0)
#   define Tcl_GlobalEvalObj(interp,objPtr) \
	Tcl_EvalObjEx((interp),(objPtr),TCL_EVAL_GLOBAL)
#endif


/*
 * These function have been renamed. The old names are deprecated, but we
 * define these macros for backwards compatibilty.
 */

#define Tcl_Ckalloc Tcl_Alloc
#define Tcl_Ckfree Tcl_Free
#define Tcl_Ckrealloc Tcl_Realloc
#define Tcl_Return Tcl_SetResult
#define Tcl_TildeSubst Tcl_TranslateFileName
#define panic Tcl_Panic
#define panicVA Tcl_PanicVA



/*
 * The following constant is used to test for older versions of Tcl
 * in the stubs tables.
 *
 * Jan Nijtman's plus patch uses 0xFCA1BACF, so we need to pick a different







>
>
|
|
|
|




<

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







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

typedef struct Tcl_Config {
    CONST char* key;   /* Configuration key to register. ASCII encoded, thus UTF-8 */
    CONST char* value; /* The value associated with the key. System encoding */
} Tcl_Config;


#ifndef TCL_NO_DEPRECATED

    /*
     * Deprecated Tcl procedures:
     */

#   define Tcl_EvalObj(interp,objPtr) \
	Tcl_EvalObjEx((interp),(objPtr),0)
#   define Tcl_GlobalEvalObj(interp,objPtr) \
	Tcl_EvalObjEx((interp),(objPtr),TCL_EVAL_GLOBAL)



    /*
     * These function have been renamed. The old names are deprecated, but
     * we define these macros for backwards compatibilty.
     */

#   define Tcl_Ckalloc Tcl_Alloc
#   define Tcl_Ckfree Tcl_Free
#   define Tcl_Ckrealloc Tcl_Realloc
#   define Tcl_Return Tcl_SetResult
#   define Tcl_TildeSubst Tcl_TranslateFileName
#   define panic Tcl_Panic
#   define panicVA Tcl_PanicVA
#endif


/*
 * The following constant is used to test for older versions of Tcl
 * in the stubs tables.
 *
 * Jan Nijtman's plus patch uses 0xFCA1BACF, so we need to pick a different
Changes to generic/tclAlloc.c.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 *
 * Portions contributed by Chris Kingsley, Jack Jansen and Ray Johnson.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclAlloc.c,v 1.16 2002/04/23 17:03:34 hobbs Exp $
 */

/*
 * Windows and Unix use an alternative allocator when building with threads
 * that has significantly reduced lock contention.
 */








|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 *
 * Portions contributed by Chris Kingsley, Jack Jansen and Ray Johnson.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclAlloc.c,v 1.16.4.1 2004/02/07 05:48:00 dgp Exp $
 */

/*
 * Windows and Unix use an alternative allocator when building with threads
 * that has significantly reduced lock contention.
 */

136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
 */

static	unsigned int nmalloc[NBUCKETS+1];
#include <stdio.h>
#endif

#if defined(DEBUG) || defined(RCHECK)
#define	ASSERT(p)   if (!(p)) panic(# p)
#define RANGE_ASSERT(p) if (!(p)) panic(# p)
#else
#define	ASSERT(p)
#define RANGE_ASSERT(p)
#endif

/*
 * Prototypes for functions used only in this file.







|
|







136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
 */

static	unsigned int nmalloc[NBUCKETS+1];
#include <stdio.h>
#endif

#if defined(DEBUG) || defined(RCHECK)
#define	ASSERT(p)   if (!(p)) Tcl_Panic(# p)
#define RANGE_ASSERT(p) if (!(p)) Tcl_Panic(# p)
#else
#define	ASSERT(p)
#define RANGE_ASSERT(p)
#endif

/*
 * Prototypes for functions used only in this file.
Changes to generic/tclBasic.c.
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 by Scriptics Corporation.
 * Copyright (c) 2001, 2002 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclBasic.c,v 1.82.2.5 2003/10/16 02:28:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"
#ifndef TCL_GENERIC_ONLY
#   include "tclPort.h"
#endif







|







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 by Scriptics Corporation.
 * Copyright (c) 2001, 2002 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclBasic.c,v 1.82.2.6 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"
#ifndef TCL_GENERIC_ONLY
#   include "tclPort.h"
#endif
110
111
112
113
114
115
116


117
118
119
120
121
122
123
        TclCompileIncrCmd,		1},
    {"info",		(Tcl_CmdProc *) NULL,	Tcl_InfoObjCmd,
        (CompileProc *) NULL,		1},
    {"join",		(Tcl_CmdProc *) NULL,	Tcl_JoinObjCmd,
        (CompileProc *) NULL,		1},
    {"lappend",		(Tcl_CmdProc *) NULL,	Tcl_LappendObjCmd,
        TclCompileLappendCmd,		1},


    {"lindex",		(Tcl_CmdProc *) NULL,	Tcl_LindexObjCmd,
        TclCompileLindexCmd,		1},
    {"linsert",		(Tcl_CmdProc *) NULL,	Tcl_LinsertObjCmd,
        (CompileProc *) NULL,		1},
    {"list",		(Tcl_CmdProc *) NULL,	Tcl_ListObjCmd,
        TclCompileListCmd,		1},
    {"llength",		(Tcl_CmdProc *) NULL,	Tcl_LlengthObjCmd,







>
>







110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
        TclCompileIncrCmd,		1},
    {"info",		(Tcl_CmdProc *) NULL,	Tcl_InfoObjCmd,
        (CompileProc *) NULL,		1},
    {"join",		(Tcl_CmdProc *) NULL,	Tcl_JoinObjCmd,
        (CompileProc *) NULL,		1},
    {"lappend",		(Tcl_CmdProc *) NULL,	Tcl_LappendObjCmd,
        TclCompileLappendCmd,		1},
    {"lassign",		(Tcl_CmdProc *) NULL,	Tcl_LassignObjCmd,
        TclCompileLassignCmd,		1},
    {"lindex",		(Tcl_CmdProc *) NULL,	Tcl_LindexObjCmd,
        TclCompileLindexCmd,		1},
    {"linsert",		(Tcl_CmdProc *) NULL,	Tcl_LinsertObjCmd,
        (CompileProc *) NULL,		1},
    {"list",		(Tcl_CmdProc *) NULL,	Tcl_ListObjCmd,
        TclCompileListCmd,		1},
    {"llength",		(Tcl_CmdProc *) NULL,	Tcl_LlengthObjCmd,
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
    /*
     * Panic if someone updated the CallFrame structure without
     * also updating the Tcl_CallFrame structure (or vice versa).
     */  

    if (sizeof(Tcl_CallFrame) != sizeof(CallFrame)) {
	/*NOTREACHED*/
        panic("Tcl_CallFrame and CallFrame are not the same size");
    }

    /*
     * Initialize support for namespaces and create the global namespace
     * (whose name is ""; an alias is "::"). This also initializes the
     * Tcl object type table and other object management code.
     */







|







291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
    /*
     * Panic if someone updated the CallFrame structure without
     * also updating the Tcl_CallFrame structure (or vice versa).
     */  

    if (sizeof(Tcl_CallFrame) != sizeof(CallFrame)) {
	/*NOTREACHED*/
        Tcl_Panic("Tcl_CallFrame and CallFrame are not the same size");
    }

    /*
     * Initialize support for namespaces and create the global namespace
     * (whose name is ""; an alias is "::"). This also initializes the
     * Tcl object type table and other object management code.
     */
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
    Tcl_IncrRefCount(iPtr->emptyObjPtr);
    iPtr->resultSpace[0] = 0;

    iPtr->globalNsPtr = NULL;	/* force creation of global ns below */
    iPtr->globalNsPtr = (Namespace *) Tcl_CreateNamespace(interp, "",
	    (ClientData) NULL, (Tcl_NamespaceDeleteProc *) NULL);
    if (iPtr->globalNsPtr == NULL) {
        panic("Tcl_CreateInterp: can't create global namespace");
    }

    /*
     * Initialize support for code compilation and execution. We call
     * TclCreateExecEnv after initializing namespaces since it tries to
     * reference a Tcl variable (it links to the Tcl "tcl_traceExec"
     * variable).







|







369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
    Tcl_IncrRefCount(iPtr->emptyObjPtr);
    iPtr->resultSpace[0] = 0;

    iPtr->globalNsPtr = NULL;	/* force creation of global ns below */
    iPtr->globalNsPtr = (Namespace *) Tcl_CreateNamespace(interp, "",
	    (ClientData) NULL, (Tcl_NamespaceDeleteProc *) NULL);
    if (iPtr->globalNsPtr == NULL) {
        Tcl_Panic("Tcl_CreateInterp: can't create global namespace");
    }

    /*
     * Initialize support for code compilation and execution. We call
     * TclCreateExecEnv after initializing namespaces since it tries to
     * reference a Tcl variable (it links to the Tcl "tcl_traceExec"
     * variable).
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
	    cmdInfoPtr++) {
	int new;
	Tcl_HashEntry *hPtr;

	if ((cmdInfoPtr->proc == (Tcl_CmdProc *) NULL)
	        && (cmdInfoPtr->objProc == (Tcl_ObjCmdProc *) NULL)
	        && (cmdInfoPtr->compileProc == (CompileProc *) NULL)) {
	    panic("Tcl_CreateInterp: builtin command with NULL string and object command procs and a NULL compile proc\n");
	}
	
	hPtr = Tcl_CreateHashEntry(&iPtr->globalNsPtr->cmdTable,
	        cmdInfoPtr->name, &new);
	if (new) {
	    cmdPtr = (Command *) ckalloc(sizeof(Command));
	    cmdPtr->hPtr = hPtr;







|







443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
	    cmdInfoPtr++) {
	int new;
	Tcl_HashEntry *hPtr;

	if ((cmdInfoPtr->proc == (Tcl_CmdProc *) NULL)
	        && (cmdInfoPtr->objProc == (Tcl_ObjCmdProc *) NULL)
	        && (cmdInfoPtr->compileProc == (CompileProc *) NULL)) {
	    Tcl_Panic("Tcl_CreateInterp: builtin command with NULL string and object command procs and a NULL compile proc\n");
	}
	
	hPtr = Tcl_CreateHashEntry(&iPtr->globalNsPtr->cmdTable,
	        cmdInfoPtr->name, &new);
	if (new) {
	    cmdPtr = (Command *) ckalloc(sizeof(Command));
	    cmdPtr->hPtr = hPtr;
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
	    builtinFuncPtr++) {
	Tcl_CreateMathFunc((Tcl_Interp *) iPtr, builtinFuncPtr->name,
		builtinFuncPtr->numArgs, builtinFuncPtr->argTypes,
		(Tcl_MathProc *) NULL, (ClientData) 0);
	hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable,
		builtinFuncPtr->name);
	if (hPtr == NULL) {
	    panic("Tcl_CreateInterp: Tcl_CreateMathFunc incorrectly registered '%s'", builtinFuncPtr->name);
	    return NULL;
	}
	mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
	mathFuncPtr->builtinFuncIndex = i;
	i++;
    }
    iPtr->flags |= EXPR_INITIALIZED;







|







491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
	    builtinFuncPtr++) {
	Tcl_CreateMathFunc((Tcl_Interp *) iPtr, builtinFuncPtr->name,
		builtinFuncPtr->numArgs, builtinFuncPtr->argTypes,
		(Tcl_MathProc *) NULL, (ClientData) 0);
	hPtr = Tcl_FindHashEntry(&iPtr->mathFuncTable,
		builtinFuncPtr->name);
	if (hPtr == NULL) {
	    Tcl_Panic("Tcl_CreateInterp: Tcl_CreateMathFunc incorrectly registered '%s'", builtinFuncPtr->name);
	    return NULL;
	}
	mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
	mathFuncPtr->builtinFuncIndex = i;
	i++;
    }
    iPtr->flags |= EXPR_INITIALIZED;
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
    ResolverScheme *resPtr, *nextResPtr;

    /*
     * Punt if there is an error in the Tcl_Release/Tcl_Preserve matchup.
     */
    
    if (iPtr->numLevels > 0) {
        panic("DeleteInterpProc called with active evals");
    }

    /*
     * The interpreter should already be marked deleted; otherwise how
     * did we get here?
     */

    if (!(iPtr->flags & DELETED)) {
        panic("DeleteInterpProc called on interpreter not marked deleted");
    }

    TclHandleFree(iPtr->handle);

    /*
     * Dismantle everything in the global namespace except for the
     * "errorInfo" and "errorCode" variables. These remain until the







|








|







973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
    ResolverScheme *resPtr, *nextResPtr;

    /*
     * 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?
     */

    if (!(iPtr->flags & DELETED)) {
        Tcl_Panic("DeleteInterpProc called on interpreter not marked deleted");
    }

    TclHandleFree(iPtr->handle);

    /*
     * Dismantle everything in the global namespace except for the
     * "errorInfo" and "errorCode" variables. These remain until the
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
     * command (enforced by Tcl_HideCommand() but let's double
     * check. (If it was not, we would not really know how to
     * handle it).
     */
    if ( cmdPtr->nsPtr != iPtr->globalNsPtr ) {
	/* 
	 * This case is theoritically impossible,
	 * we might rather panic() than 'nicely' erroring out ?
	 */
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
                "trying to expose a non global command name space command",
		(char *) NULL);
        return TCL_ERROR;
    }
    







|







1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
     * command (enforced by Tcl_HideCommand() but let's double
     * check. (If it was not, we would not really know how to
     * handle it).
     */
    if ( cmdPtr->nsPtr != iPtr->globalNsPtr ) {
	/* 
	 * This case is theoritically impossible,
	 * we might rather Tcl_Panic() than 'nicely' erroring out ?
	 */
        Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
                "trying to expose a non global command name space command",
		(char *) NULL);
        return TCL_ERROR;
    }
    
Changes to generic/tclBinary.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclBinary.c --
 *
 *	This file contains the implementation of the "binary" Tcl built-in
 *	command and the Tcl binary data object.
 *
 * Copyright (c) 1997 by 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.
 *
 * RCS: @(#) $Id: tclBinary.c,v 1.13 2003/02/21 21:54:11 dkf Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include <math.h>

/*












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclBinary.c --
 *
 *	This file contains the implementation of the "binary" Tcl built-in
 *	command and the Tcl binary data object.
 *
 * Copyright (c) 1997 by 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.
 *
 * RCS: @(#) $Id: tclBinary.c,v 1.13.4.1 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include <math.h>

/*
57
58
59
60
61
62
63
64

65
66
67
68
69
70
71
static int		GetFormatSpec _ANSI_ARGS_((char **formatPtr,
			    char *cmdPtr, int *countPtr));
static Tcl_Obj *	ScanNumber _ANSI_ARGS_((unsigned char *buffer,
			    int type, Tcl_HashTable **numberCachePtr));
static int		SetByteArrayFromAny _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *objPtr));
static void		UpdateStringOfByteArray _ANSI_ARGS_((Tcl_Obj *listPtr));



/*
 * The following object type represents an array of bytes.  An array of
 * bytes is not equivalent to an internationalized string.  Conceptually, a
 * string is an array of 16-bit quantities organized as a sequence of properly
 * formed UTF-8 characters, while a ByteArray is an array of 8-bit quantities.
 * Accessor functions are provided to convert a ByteArray to a String or a







|
>







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
static int		GetFormatSpec _ANSI_ARGS_((char **formatPtr,
			    char *cmdPtr, int *countPtr));
static Tcl_Obj *	ScanNumber _ANSI_ARGS_((unsigned char *buffer,
			    int type, Tcl_HashTable **numberCachePtr));
static int		SetByteArrayFromAny _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *objPtr));
static void		UpdateStringOfByteArray _ANSI_ARGS_((Tcl_Obj *listPtr));
static void		DeleteScanNumberCache _ANSI_ARGS_((
			    Tcl_HashTable *numberCachePtr));

/*
 * The following object type represents an array of bytes.  An array of
 * bytes is not equivalent to an internationalized string.  Conceptually, a
 * string is an array of 16-bit quantities organized as a sequence of properly
 * formed UTF-8 characters, while a ByteArray is an array of 8-bit quantities.
 * Accessor functions are provided to convert a ByteArray to a String or a
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
    int length;			/* Length of the array of bytes, which must
				 * be >= 0. */
{
    Tcl_ObjType *typePtr;
    ByteArray *byteArrayPtr;

    if (Tcl_IsShared(objPtr)) {
	panic("Tcl_SetByteArrayObj called with shared object");
    }
    typePtr = objPtr->typePtr;
    if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
	(*typePtr->freeIntRepProc)(objPtr);
    }
    Tcl_InvalidateStringRep(objPtr);








|







261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
    int length;			/* Length of the array of bytes, which must
				 * be >= 0. */
{
    Tcl_ObjType *typePtr;
    ByteArray *byteArrayPtr;

    if (Tcl_IsShared(objPtr)) {
	Tcl_Panic("Tcl_SetByteArrayObj called with shared object");
    }
    typePtr = objPtr->typePtr;
    if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
	(*typePtr->freeIntRepProc)(objPtr);
    }
    Tcl_InvalidateStringRep(objPtr);

342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
Tcl_SetByteArrayLength(objPtr, length)
    Tcl_Obj *objPtr;		/* The ByteArray object. */
    int length;			/* New length for internal byte array. */
{
    ByteArray *byteArrayPtr, *newByteArrayPtr;
    
    if (Tcl_IsShared(objPtr)) {
	panic("Tcl_SetObjLength called with shared object");
    }
    if (objPtr->typePtr != &tclByteArrayType) {
	SetByteArrayFromAny(NULL, objPtr);
    }

    byteArrayPtr = GET_BYTEARRAY(objPtr);
    if (length > byteArrayPtr->allocated) {







|







343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
Tcl_SetByteArrayLength(objPtr, length)
    Tcl_Obj *objPtr;		/* The ByteArray object. */
    int length;			/* New length for internal byte array. */
{
    ByteArray *byteArrayPtr, *newByteArrayPtr;
    
    if (Tcl_IsShared(objPtr)) {
	Tcl_Panic("Tcl_SetObjLength called with shared object");
    }
    if (objPtr->typePtr != &tclByteArrayType) {
	SetByteArrayFromAny(NULL, objPtr);
    }

    byteArrayPtr = GET_BYTEARRAY(objPtr);
    if (length > byteArrayPtr->allocated) {
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
			} else {
			    offset = count;
			}
			break;
		    }
		    default: {
			errorString = str;
			goto badfield;
		    }
		}
	    }
	    if (offset > length) {
		length = offset;
	    }
	    if (length == 0) {







|







748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
			} else {
			    offset = count;
			}
			break;
		    }
		    default: {
			errorString = str;
			goto badField;
		    }
		}
	    }
	    if (offset > length) {
		length = offset;
	    }
	    if (length == 0) {
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
		}
		switch (cmd) {
		    case 'a':
		    case 'A': {
			unsigned char *src;

			if (arg >= objc) {
			    if (numberCachePtr != NULL) {
				Tcl_DeleteHashTable(numberCachePtr);
			    }
			    goto badIndex;
			}
			if (count == BINARY_ALL) {
			    count = length - offset;
			} else {
			    if (count == BINARY_NOCOUNT) {
				count = 1;







|
<
<







1047
1048
1049
1050
1051
1052
1053
1054


1055
1056
1057
1058
1059
1060
1061
		}
		switch (cmd) {
		    case 'a':
		    case 'A': {
			unsigned char *src;

			if (arg >= objc) {
			    DeleteScanNumberCache(numberCachePtr);


			    goto badIndex;
			}
			if (count == BINARY_ALL) {
			    count = length - offset;
			} else {
			    if (count == BINARY_NOCOUNT) {
				count = 1;
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
			    }
			}
			valuePtr = Tcl_NewByteArrayObj(src, size);
			resultPtr = Tcl_ObjSetVar2(interp, objv[arg],
				NULL, valuePtr, TCL_LEAVE_ERR_MSG);
			arg++;
			if (resultPtr == NULL) {
			    if (numberCachePtr != NULL) {
				Tcl_DeleteHashTable(numberCachePtr);
			    }
			    Tcl_DecrRefCount(valuePtr);	/* unneeded */
			    return TCL_ERROR;
			}
			offset += count;
			break;
		    }
		    case 'b':
		    case 'B': {
			unsigned char *src;
			char *dest;

			if (arg >= objc) {
			    if (numberCachePtr != NULL) {
				Tcl_DeleteHashTable(numberCachePtr);
			    }
			    goto badIndex;
			}
			if (count == BINARY_ALL) {
			    count = (length - offset) * 8;
			} else {
			    if (count == BINARY_NOCOUNT) {
				count = 1;







|
<
<












|
<
<







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
			    }
			}
			valuePtr = Tcl_NewByteArrayObj(src, size);
			resultPtr = Tcl_ObjSetVar2(interp, objv[arg],
				NULL, valuePtr, TCL_LEAVE_ERR_MSG);
			arg++;
			if (resultPtr == NULL) {
			    DeleteScanNumberCache(numberCachePtr);


			    Tcl_DecrRefCount(valuePtr);	/* unneeded */
			    return TCL_ERROR;
			}
			offset += count;
			break;
		    }
		    case 'b':
		    case 'B': {
			unsigned char *src;
			char *dest;

			if (arg >= objc) {
			    DeleteScanNumberCache(numberCachePtr);


			    goto badIndex;
			}
			if (count == BINARY_ALL) {
			    count = (length - offset) * 8;
			} else {
			    if (count == BINARY_NOCOUNT) {
				count = 1;
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
			    }
			}
			
			resultPtr = Tcl_ObjSetVar2(interp, objv[arg],
				NULL, valuePtr, TCL_LEAVE_ERR_MSG);
			arg++;
			if (resultPtr == NULL) {
			    if (numberCachePtr != NULL) {
				Tcl_DeleteHashTable(numberCachePtr);
			    }
			    Tcl_DecrRefCount(valuePtr);	/* unneeded */
			    return TCL_ERROR;
			}
			offset += (count + 7 ) / 8;
			break;
		    }
		    case 'h':
		    case 'H': {
			char *dest;
			unsigned char *src;
			int i;
			static char hexdigit[] = "0123456789abcdef";

			if (arg >= objc) {
			    if (numberCachePtr != NULL) {
				Tcl_DeleteHashTable(numberCachePtr);
			    }
			    goto badIndex;
			}
			if (count == BINARY_ALL) {
			    count = (length - offset)*2;
			} else {
			    if (count == BINARY_NOCOUNT) {
				count = 1;







|
<
<














|
<
<







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
			    }
			}
			
			resultPtr = Tcl_ObjSetVar2(interp, objv[arg],
				NULL, valuePtr, TCL_LEAVE_ERR_MSG);
			arg++;
			if (resultPtr == NULL) {
			    DeleteScanNumberCache(numberCachePtr);


			    Tcl_DecrRefCount(valuePtr);	/* unneeded */
			    return TCL_ERROR;
			}
			offset += (count + 7 ) / 8;
			break;
		    }
		    case 'h':
		    case 'H': {
			char *dest;
			unsigned char *src;
			int i;
			static char hexdigit[] = "0123456789abcdef";

			if (arg >= objc) {
			    DeleteScanNumberCache(numberCachePtr);


			    goto badIndex;
			}
			if (count == BINARY_ALL) {
			    count = (length - offset)*2;
			} else {
			    if (count == BINARY_NOCOUNT) {
				count = 1;
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
			    }
			}
			
			resultPtr = Tcl_ObjSetVar2(interp, objv[arg],
				NULL, valuePtr, TCL_LEAVE_ERR_MSG);
			arg++;
			if (resultPtr == NULL) {
			    if (numberCachePtr != NULL) {
				Tcl_DeleteHashTable(numberCachePtr);
			    }
			    Tcl_DecrRefCount(valuePtr);	/* unneeded */
			    return TCL_ERROR;
			}
			offset += (count + 1) / 2;
			break;
		    }
		    case 'c': {







|
<
<







1193
1194
1195
1196
1197
1198
1199
1200


1201
1202
1203
1204
1205
1206
1207
			    }
			}
			
			resultPtr = Tcl_ObjSetVar2(interp, objv[arg],
				NULL, valuePtr, TCL_LEAVE_ERR_MSG);
			arg++;
			if (resultPtr == NULL) {
			    DeleteScanNumberCache(numberCachePtr);


			    Tcl_DecrRefCount(valuePtr);	/* unneeded */
			    return TCL_ERROR;
			}
			offset += (count + 1) / 2;
			break;
		    }
		    case 'c': {
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
			unsigned char *src;

			size = sizeof(double);
			/* fall through */
			
			scanNumber:
			if (arg >= objc) {
			    if (numberCachePtr != NULL) {
				Tcl_DeleteHashTable(numberCachePtr);
			    }
			    goto badIndex;
			}
			if (count == BINARY_NOCOUNT) {
			    if ((length - offset) < size) {
				goto done;
			    }
			    valuePtr = ScanNumber(buffer+offset, cmd,







|
<
<







1231
1232
1233
1234
1235
1236
1237
1238


1239
1240
1241
1242
1243
1244
1245
			unsigned char *src;

			size = sizeof(double);
			/* fall through */
			
			scanNumber:
			if (arg >= objc) {
			    DeleteScanNumberCache(numberCachePtr);


			    goto badIndex;
			}
			if (count == BINARY_NOCOUNT) {
			    if ((length - offset) < size) {
				goto done;
			    }
			    valuePtr = ScanNumber(buffer+offset, cmd,
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
			    offset += count*size;
			}

			resultPtr = Tcl_ObjSetVar2(interp, objv[arg],
				NULL, valuePtr, TCL_LEAVE_ERR_MSG);
			arg++;
			if (resultPtr == NULL) {
			    if (numberCachePtr != NULL) {
				Tcl_DeleteHashTable(numberCachePtr);
			    }
			    Tcl_DecrRefCount(valuePtr);	/* unneeded */
			    return TCL_ERROR;
			}
			break;
		    }
		    case 'x': {
			if (count == BINARY_NOCOUNT) {







|
<
<







1264
1265
1266
1267
1268
1269
1270
1271


1272
1273
1274
1275
1276
1277
1278
			    offset += count*size;
			}

			resultPtr = Tcl_ObjSetVar2(interp, objv[arg],
				NULL, valuePtr, TCL_LEAVE_ERR_MSG);
			arg++;
			if (resultPtr == NULL) {
			    DeleteScanNumberCache(numberCachePtr);


			    Tcl_DecrRefCount(valuePtr);	/* unneeded */
			    return TCL_ERROR;
			}
			break;
		    }
		    case 'x': {
			if (count == BINARY_NOCOUNT) {
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
			} else {
			    offset -= count;
			}
			break;
		    }
		    case '@': {
			if (count == BINARY_NOCOUNT) {
			    if (numberCachePtr != NULL) {
				Tcl_DeleteHashTable(numberCachePtr);
			    }
			    goto badCount;
			}
			if ((count == BINARY_ALL) || (count > length)) {
			    offset = length;
			} else {
			    offset = count;
			}
			break;
		    }
		    default: {
			if (numberCachePtr != NULL) {
			    Tcl_DeleteHashTable(numberCachePtr);
			}
			errorString = str;
			goto badfield;
		    }
		}
	    }

	    /*
	     * Set the result to the last position of the cursor.
	     */

	    done:
	    Tcl_ResetResult(interp);
	    Tcl_SetLongObj(Tcl_GetObjResult(interp), arg - 4);
	    if (numberCachePtr != NULL) {
		Tcl_DeleteHashTable(numberCachePtr);
	    }
	    break;
	}
    }
    return TCL_OK;

    badValue:
    Tcl_ResetResult(interp);
    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "expected ", errorString,
	    " string but got \"", errorValue, "\" instead", NULL);
    return TCL_ERROR;

    badCount:
    errorString = "missing count for \"@\" field specifier";
    goto error;

    badIndex:
    errorString = "not enough arguments for all format specifiers";
    goto error;

    badfield: {

	Tcl_UniChar ch;
	char buf[TCL_UTF_MAX + 1];

	Tcl_UtfToUniChar(errorString, &ch);
	buf[Tcl_UniCharToUtf(ch, buf)] = '\0';
	Tcl_AppendResult(interp, "bad field specifier \"", buf, "\"", NULL);
	return TCL_ERROR;







|
<
<










|
<
<

|











|
<
<



















|
>







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
			} else {
			    offset -= count;
			}
			break;
		    }
		    case '@': {
			if (count == BINARY_NOCOUNT) {
			    DeleteScanNumberCache(numberCachePtr);


			    goto badCount;
			}
			if ((count == BINARY_ALL) || (count > length)) {
			    offset = length;
			} else {
			    offset = count;
			}
			break;
		    }
		    default: {
			DeleteScanNumberCache(numberCachePtr);


			errorString = str;
			goto badField;
		    }
		}
	    }

	    /*
	     * Set the result to the last position of the cursor.
	     */

	    done:
	    Tcl_ResetResult(interp);
	    Tcl_SetLongObj(Tcl_GetObjResult(interp), arg - 4);
	    DeleteScanNumberCache(numberCachePtr);


	    break;
	}
    }
    return TCL_OK;

    badValue:
    Tcl_ResetResult(interp);
    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "expected ", errorString,
	    " string but got \"", errorValue, "\" instead", NULL);
    return TCL_ERROR;

    badCount:
    errorString = "missing count for \"@\" field specifier";
    goto error;

    badIndex:
    errorString = "not enough arguments for all format specifiers";
    goto error;

    badField:
    {
	Tcl_UniChar ch;
	char buf[TCL_UTF_MAX + 1];

	Tcl_UtfToUniChar(errorString, &ch);
	buf[Tcl_UniCharToUtf(ch, buf)] = '\0';
	Tcl_AppendResult(interp, "bad field specifier \"", buf, "\"", NULL);
	return TCL_ERROR;
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









































		     * a LOT of varied binary data in a single call!
		     * Bail out by switching back to the old behaviour
		     * for the rest of the scan.
		     *
		     * Note that anyone just using the 'c' conversion
		     * (for bytes) cannot trigger this.
		     */
		    Tcl_DeleteHashTable(tablePtr);
		    *numberCachePtrPtr = NULL;
		    return Tcl_NewLongObj(value);
		} else {
		    register Tcl_Obj *objPtr = Tcl_NewLongObj(value);
		    /* Don't need to fiddle with refcount... */

		    Tcl_SetHashValue(hPtr, (ClientData) objPtr);
		    return objPtr;
		}
	    }





	case 'w':
	    uwvalue =  ((Tcl_WideUInt) buffer[0])
		    | (((Tcl_WideUInt) buffer[1]) << 8)
		    | (((Tcl_WideUInt) buffer[2]) << 16)
		    | (((Tcl_WideUInt) buffer[3]) << 24)
		    | (((Tcl_WideUInt) buffer[4]) << 32)
		    | (((Tcl_WideUInt) buffer[5]) << 40)
		    | (((Tcl_WideUInt) buffer[6]) << 48)
		    | (((Tcl_WideUInt) buffer[7]) << 56);
	    return Tcl_NewWideIntObj((Tcl_WideInt) uwvalue);
	case 'W':
	    uwvalue =  ((Tcl_WideUInt) buffer[7])
		    | (((Tcl_WideUInt) buffer[6]) << 8)
		    | (((Tcl_WideUInt) buffer[5]) << 16)
		    | (((Tcl_WideUInt) buffer[4]) << 24)
		    | (((Tcl_WideUInt) buffer[3]) << 32)
		    | (((Tcl_WideUInt) buffer[2]) << 40)
		    | (((Tcl_WideUInt) buffer[1]) << 48)
		    | (((Tcl_WideUInt) buffer[0]) << 56);
	    return Tcl_NewWideIntObj((Tcl_WideInt) uwvalue);






	case 'f': {
	    float fvalue;
	    memcpy((VOID *) &fvalue, (VOID *) buffer, sizeof(float));
	    return Tcl_NewDoubleObj(fvalue);
	}
	case 'd': {
	    double dvalue;
	    memcpy((VOID *) &dvalue, (VOID *) buffer, sizeof(double));
	    return Tcl_NewDoubleObj(dvalue);
	}
    }
    return NULL;
}
















































|




|
>




>
>
>
>
>




















>
>
>
>
>
>













>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
		     * a LOT of varied binary data in a single call!
		     * Bail out by switching back to the old behaviour
		     * for the rest of the scan.
		     *
		     * Note that anyone just using the 'c' conversion
		     * (for bytes) cannot trigger this.
		     */
		    DeleteScanNumberCache(tablePtr);
		    *numberCachePtrPtr = NULL;
		    return Tcl_NewLongObj(value);
		} else {
		    register Tcl_Obj *objPtr = Tcl_NewLongObj(value);

		    Tcl_IncrRefCount(objPtr);
		    Tcl_SetHashValue(hPtr, (ClientData) objPtr);
		    return objPtr;
		}
	    }

	    /*
	     * Do not cache wide values; they are already too large to
	     * use as keys.
	     */
	case 'w':
	    uwvalue =  ((Tcl_WideUInt) buffer[0])
		    | (((Tcl_WideUInt) buffer[1]) << 8)
		    | (((Tcl_WideUInt) buffer[2]) << 16)
		    | (((Tcl_WideUInt) buffer[3]) << 24)
		    | (((Tcl_WideUInt) buffer[4]) << 32)
		    | (((Tcl_WideUInt) buffer[5]) << 40)
		    | (((Tcl_WideUInt) buffer[6]) << 48)
		    | (((Tcl_WideUInt) buffer[7]) << 56);
	    return Tcl_NewWideIntObj((Tcl_WideInt) uwvalue);
	case 'W':
	    uwvalue =  ((Tcl_WideUInt) buffer[7])
		    | (((Tcl_WideUInt) buffer[6]) << 8)
		    | (((Tcl_WideUInt) buffer[5]) << 16)
		    | (((Tcl_WideUInt) buffer[4]) << 24)
		    | (((Tcl_WideUInt) buffer[3]) << 32)
		    | (((Tcl_WideUInt) buffer[2]) << 40)
		    | (((Tcl_WideUInt) buffer[1]) << 48)
		    | (((Tcl_WideUInt) buffer[0]) << 56);
	    return Tcl_NewWideIntObj((Tcl_WideInt) uwvalue);

	    /*
	     * Do not cache double values; they are already too large
	     * to use as keys and the values stored are utterly
	     * incompatible too.
	     */
	case 'f': {
	    float fvalue;
	    memcpy((VOID *) &fvalue, (VOID *) buffer, sizeof(float));
	    return Tcl_NewDoubleObj(fvalue);
	}
	case 'd': {
	    double dvalue;
	    memcpy((VOID *) &dvalue, (VOID *) buffer, sizeof(double));
	    return Tcl_NewDoubleObj(dvalue);
	}
    }
    return NULL;
}

/*
 *----------------------------------------------------------------------
 *
 * DeleteScanNumberCache --
 * 
 *	Deletes the hash table acting as a scan number cache.
 *
 * Results:
 *	None
 *
 * Side effects:
 *	Decrements the reference counts of the objects in the cache.
 *
 *----------------------------------------------------------------------
 */

static void
DeleteScanNumberCache(numberCachePtr)
    Tcl_HashTable *numberCachePtr;	/* Pointer to the hash table, or
					 * NULL (when the cache has already
					 * been deleted due to overflow.) */
{
    Tcl_HashEntry *hEntry;
    Tcl_HashSearch search;

    if (numberCachePtr == NULL) {
	return;
    }

    hEntry = Tcl_FirstHashEntry(numberCachePtr, &search);
    while (hEntry != NULL) {
	register Tcl_Obj *value = (Tcl_Obj *) Tcl_GetHashValue(hEntry);

	if (value != NULL) {
	    Tcl_DecrRefCount(value);
	}
	hEntry = Tcl_NextHashEntry(&search);
    }
    Tcl_DeleteHashTable(numberCachePtr);
}
Changes to generic/tclCkalloc.c.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 * 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.
 *
 * This code contributed by Karl Lehenbauer and Mark Diekhans
 *
 * RCS: @(#) $Id: tclCkalloc.c,v 1.19 2003/01/19 07:21:18 hobbs Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

#define FALSE	0
#define TRUE	1







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 * 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.
 *
 * This code contributed by Karl Lehenbauer and Mark Diekhans
 *
 * RCS: @(#) $Id: tclCkalloc.c,v 1.19.4.1 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

#define FALSE	0
#define TRUE	1
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
    if (guard_failed) {
        TclDumpMemoryInfo (stderr);
        fprintf(stderr, "low guard failed at %lx, %s %d\n",
                 (long unsigned int) memHeaderP->body, file, line);
        fflush(stderr);  /* In case name pointer is bad. */
        fprintf(stderr, "%ld bytes allocated at (%s %d)\n", memHeaderP->length,
		memHeaderP->file, memHeaderP->line);
        panic ("Memory validation failure");
    }

    hiPtr = (unsigned char *)memHeaderP->body + memHeaderP->length;
    for (idx = 0; idx < HIGH_GUARD_SIZE; idx++) {
        byte = *(hiPtr + idx);
        if (byte != GUARD_VALUE) {
            guard_failed = TRUE;







|







227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
    if (guard_failed) {
        TclDumpMemoryInfo (stderr);
        fprintf(stderr, "low guard failed at %lx, %s %d\n",
                 (long unsigned int) memHeaderP->body, file, line);
        fflush(stderr);  /* In case name pointer is bad. */
        fprintf(stderr, "%ld bytes allocated at (%s %d)\n", memHeaderP->length,
		memHeaderP->file, memHeaderP->line);
        Tcl_Panic("Memory validation failure");
    }

    hiPtr = (unsigned char *)memHeaderP->body + memHeaderP->length;
    for (idx = 0; idx < HIGH_GUARD_SIZE; idx++) {
        byte = *(hiPtr + idx);
        if (byte != GUARD_VALUE) {
            guard_failed = TRUE;
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
        TclDumpMemoryInfo (stderr);
        fprintf(stderr, "high guard failed at %lx, %s %d\n",
                 (long unsigned int) memHeaderP->body, file, line);
        fflush(stderr);  /* In case name pointer is bad. */
        fprintf(stderr, "%ld bytes allocated at (%s %d)\n",
		memHeaderP->length, memHeaderP->file,
		memHeaderP->line);
        panic("Memory validation failure");
    }

    if (nukeGuards) {
        memset ((char *) memHeaderP->low_guard, 0, LOW_GUARD_SIZE); 
        memset ((char *) hiPtr, 0, HIGH_GUARD_SIZE); 
    }








|







250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
        TclDumpMemoryInfo (stderr);
        fprintf(stderr, "high guard failed at %lx, %s %d\n",
                 (long unsigned int) memHeaderP->body, file, line);
        fflush(stderr);  /* In case name pointer is bad. */
        fprintf(stderr, "%ld bytes allocated at (%s %d)\n",
		memHeaderP->length, memHeaderP->file,
		memHeaderP->line);
        Tcl_Panic("Memory validation failure");
    }

    if (nukeGuards) {
        memset ((char *) memHeaderP->low_guard, 0, LOW_GUARD_SIZE); 
        memset ((char *) hiPtr, 0, HIGH_GUARD_SIZE); 
    }

374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
        Tcl_ValidateAllMemory (file, line);

    result = (struct mem_header *) TclpAlloc((unsigned)size + 
                              sizeof(struct mem_header) + HIGH_GUARD_SIZE);
    if (result == NULL) {
        fflush(stdout);
        TclDumpMemoryInfo(stderr);
        panic("unable to alloc %u bytes, %s line %d", size, file, line);
    }

    /*
     * Fill in guard zones and size.  Also initialize the contents of
     * the block with bogus bytes to detect uses of initialized data.
     * Link into allocated list.
     */







|







374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
        Tcl_ValidateAllMemory (file, line);

    result = (struct mem_header *) TclpAlloc((unsigned)size + 
                              sizeof(struct mem_header) + HIGH_GUARD_SIZE);
    if (result == NULL) {
        fflush(stdout);
        TclDumpMemoryInfo(stderr);
        Tcl_Panic("unable to alloc %u bytes, %s line %d", size, file, line);
    }

    /*
     * Fill in guard zones and size.  Also initialize the contents of
     * the block with bogus bytes to detect uses of initialized data.
     * Link into allocated list.
     */
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549

/*
 *----------------------------------------------------------------------
 *
 * Tcl_DbCkfree - debugging ckfree
 *
 *        Verify that the low and high guards are intact, and if so
 *        then free the buffer else panic.
 *
 *        The guards are erased after being checked to catch duplicate
 *        frees.
 *
 *        The second and third arguments are file and line, these contain
 *        the filename and line number corresponding to the caller.
 *        These are sent by the ckfree macro; it uses the preprocessor







|







535
536
537
538
539
540
541
542
543
544
545
546
547
548
549

/*
 *----------------------------------------------------------------------
 *
 * Tcl_DbCkfree - debugging ckfree
 *
 *        Verify that the low and high guards are intact, and if so
 *        then free the buffer else Tcl_Panic.
 *
 *        The guards are erased after being checked to catch duplicate
 *        frees.
 *
 *        The second and third arguments are file and line, these contain
 *        the filename and line number corresponding to the caller.
 *        These are sent by the ckfree macro; it uses the preprocessor
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
     * by returning NULL, so we have to check that the NULL we get is
     * not in response to alloc(0).
     *
     * The ANSI spec actually says that systems either return NULL *or*
     * a special pointer on failure, but we only check for NULL
     */
    if ((result == NULL) && size) {
	panic("unable to alloc %u bytes", size);
    }
    return result;
}

char *
Tcl_DbCkalloc(size, file, line)
    unsigned int size;
    CONST char  *file;
    int          line;
{
    char *result;

    result = (char *) TclpAlloc(size);

    if ((result == NULL) && size) {
        fflush(stdout);
        panic("unable to alloc %u bytes, %s line %d", size, file, line);
    }
    return result;
}

/*
 *----------------------------------------------------------------------
 *







|
















|







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
     * by returning NULL, so we have to check that the NULL we get is
     * not in response to alloc(0).
     *
     * The ANSI spec actually says that systems either return NULL *or*
     * a special pointer on failure, but we only check for NULL
     */
    if ((result == NULL) && size) {
	Tcl_Panic("unable to alloc %u bytes", size);
    }
    return result;
}

char *
Tcl_DbCkalloc(size, file, line)
    unsigned int size;
    CONST char  *file;
    int          line;
{
    char *result;

    result = (char *) TclpAlloc(size);

    if ((result == NULL) && size) {
        fflush(stdout);
        Tcl_Panic("unable to alloc %u bytes, %s line %d", size, file, line);
    }
    return result;
}

/*
 *----------------------------------------------------------------------
 *
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
    unsigned int size;
{
    char *result;

    result = TclpRealloc(ptr, size);

    if ((result == NULL) && size) {
	panic("unable to realloc %u bytes", size);
    }
    return result;
}

char *
Tcl_DbCkrealloc(ptr, size, file, line)
    char        *ptr;
    unsigned int size;
    CONST char  *file;
    int          line;
{
    char *result;

    result = (char *) TclpRealloc(ptr, size);

    if ((result == NULL) && size) {
        fflush(stdout);
        panic("unable to realloc %u bytes, %s line %d", size, file, line);
    }
    return result;
}

/*
 *----------------------------------------------------------------------
 *







|

















|







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
    unsigned int size;
{
    char *result;

    result = TclpRealloc(ptr, size);

    if ((result == NULL) && size) {
	Tcl_Panic("unable to realloc %u bytes", size);
    }
    return result;
}

char *
Tcl_DbCkrealloc(ptr, size, file, line)
    char        *ptr;
    unsigned int size;
    CONST char  *file;
    int          line;
{
    char *result;

    result = (char *) TclpRealloc(ptr, size);

    if ((result == NULL) && size) {
        fflush(stdout);
        Tcl_Panic("unable to realloc %u bytes, %s line %d", size, file, line);
    }
    return result;
}

/*
 *----------------------------------------------------------------------
 *
Changes to generic/tclClock.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclClock.c --
 *
 *	Contains the time and date related commands.  This code
 *	is derived from the time and date facilities of TclX,
 *	by Mark Diekhans and Karl Lehenbauer.
 *
 * Copyright 1991-1995 Karl Lehenbauer and Mark Diekhans.
 * Copyright (c) 1995 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclClock.c,v 1.23 2003/05/18 19:48:26 kennykb Exp $
 */

#include "tcl.h"
#include "tclInt.h"
#include "tclPort.h"

/*













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclClock.c --
 *
 *	Contains the time and date related commands.  This code
 *	is derived from the time and date facilities of TclX,
 *	by Mark Diekhans and Karl Lehenbauer.
 *
 * Copyright 1991-1995 Karl Lehenbauer and Mark Diekhans.
 * Copyright (c) 1995 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclClock.c,v 1.23.2.1 2004/02/07 05:48:00 dgp Exp $
 */

#include "tcl.h"
#include "tclInt.h"
#include "tclPort.h"

/*
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
    int clickType = 2;
    int dummy;
    unsigned long baseClock, clockVal;
    long zone;
    Tcl_Obj *baseObjPtr = NULL;
    char *scanStr;
    Tcl_Time now;		/* Current time */
    
    static CONST char *switches[] =
	{"clicks", "format", "scan", "seconds", (char *) NULL};

    enum command { COMMAND_CLICKS, COMMAND_FORMAT, COMMAND_SCAN,
		       COMMAND_SECONDS
    };
    static CONST char *clicksSwitches[] = {"-milliseconds", "-microseconds",
					   (char*) NULL};

    static CONST char *formatSwitches[] = {"-format", "-gmt", (char *) NULL};


    static CONST char *scanSwitches[] = {"-base", "-gmt", (char *) NULL};



    resultPtr = Tcl_GetObjResult(interp);
    if (objc < 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
	return TCL_ERROR;
    }

    if (Tcl_GetIndexFromObj(interp, objv[1], switches, "option", 0, &index)
	    != TCL_OK) {
	return TCL_ERROR;
    }
    switch ((enum command) index) {
	case COMMAND_CLICKS:	{		/* clicks */

	    if (objc == 3) {
		if ( Tcl_GetIndexFromObj( interp, objv[2], clicksSwitches,
					  "option", 0, &clickType )
		     != TCL_OK ) {
		    return TCL_ERROR;
		}
	    } else if (objc != 2) {
		Tcl_WrongNumArgs(interp, 2, objv, "?-milliseconds?");
		return TCL_ERROR;
	    }
	    switch ( clickType ) {
	    case 0: 		/* milliseconds */
		Tcl_GetTime( &now );
		Tcl_SetWideIntObj( resultPtr,
				   ( (Tcl_WideInt) now.sec * 1000
				     + now.usec / 1000 ) );
		break;
	    case 1:		/* microseconds */
		Tcl_GetTime( &now );
		Tcl_SetWideIntObj( resultPtr,
				   ( (Tcl_WideInt) now.sec * 1000000
				     + now.usec ) );
		break;
	    case 2:		/* native clicks */
		Tcl_SetWideIntObj( resultPtr,
				   (Tcl_WideInt) TclpGetClicks() );
		break;
	    }

	    return TCL_OK;
	}

	case COMMAND_FORMAT:			/* format */
	    if ((objc < 3) || (objc > 7)) {
		wrongFmtArgs:
		Tcl_WrongNumArgs(interp, 2, objv,
			"clockval ?-format string? ?-gmt boolean?");
		return TCL_ERROR;
	    }

	    if (Tcl_GetLongFromObj(interp, objv[2], (long*) &clockVal)
		    != TCL_OK) {
		return TCL_ERROR;
	    }
    
	    objPtr = objv+3;
	    objc -= 3;
	    while (objc > 1) {
		if (Tcl_GetIndexFromObj(interp, objPtr[0], formatSwitches,
			"switch", 0, &index) != TCL_OK) {
		    return TCL_ERROR;
		}







|
|
|
>
|
|

|
|
>
|
>
>
|
>
>













<

|
|
<






|

|
|
|
<


|
|
|
<


<
|


















|







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
    int clickType = 2;
    int dummy;
    unsigned long baseClock, clockVal;
    long zone;
    Tcl_Obj *baseObjPtr = NULL;
    char *scanStr;
    Tcl_Time now;		/* Current time */

    static CONST char *switches[] = {
	"clicks", "format", "scan", "seconds", (char *) NULL
    };
    enum command {
	COMMAND_CLICKS, COMMAND_FORMAT, COMMAND_SCAN, COMMAND_SECONDS
    };
    static CONST char *clicksSwitches[] = {
	"-milliseconds", "-microseconds", (char*) NULL
    };
    static CONST char *formatSwitches[] = {
	"-format", "-gmt", (char *) NULL
    };
    static CONST char *scanSwitches[] = {
	"-base", "-gmt", (char *) NULL
    };

    resultPtr = Tcl_GetObjResult(interp);
    if (objc < 2) {
	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
	return TCL_ERROR;
    }

    if (Tcl_GetIndexFromObj(interp, objv[1], switches, "option", 0, &index)
	    != TCL_OK) {
	return TCL_ERROR;
    }
    switch ((enum command) index) {
	case COMMAND_CLICKS:	{		/* clicks */

	    if (objc == 3) {
		if (Tcl_GetIndexFromObj(interp, objv[2], clicksSwitches,
			"option", 0, &clickType) != TCL_OK) {

		    return TCL_ERROR;
		}
	    } else if (objc != 2) {
		Tcl_WrongNumArgs(interp, 2, objv, "?-milliseconds?");
		return TCL_ERROR;
	    }
	    switch (clickType) {
	    case 0: 		/* milliseconds */
		Tcl_GetTime(&now);
		Tcl_SetWideIntObj(resultPtr,
			((Tcl_WideInt) now.sec * 1000 + now.usec / 1000));

		break;
	    case 1:		/* microseconds */
		Tcl_GetTime(&now);
		Tcl_SetWideIntObj(resultPtr,
			((Tcl_WideInt) now.sec * 1000000 + now.usec));

		break;
	    case 2:		/* native clicks */

		Tcl_SetWideIntObj(resultPtr, (Tcl_WideInt) TclpGetClicks());
		break;
	    }

	    return TCL_OK;
	}

	case COMMAND_FORMAT:			/* format */
	    if ((objc < 3) || (objc > 7)) {
		wrongFmtArgs:
		Tcl_WrongNumArgs(interp, 2, objv,
			"clockval ?-format string? ?-gmt boolean?");
		return TCL_ERROR;
	    }

	    if (Tcl_GetLongFromObj(interp, objv[2], (long*) &clockVal)
		    != TCL_OK) {
		return TCL_ERROR;
	    }

	    objPtr = objv+3;
	    objc -= 3;
	    while (objc > 1) {
		if (Tcl_GetIndexFromObj(interp, objPtr[0], formatSwitches,
			"switch", 0, &index) != TCL_OK) {
		    return TCL_ERROR;
		}
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
     * This is a kludge for systems not having the timezone string in
     * struct tm.  No matter what was specified, they use the local
     * timezone string.  Since this kludge requires fiddling with the
     * TZ environment variable, it will mess up if done on multiple
     * threads at once.  Protect it with a the clock mutex.
     */

    Tcl_MutexLock( &clockMutex );
    if (useGMT) {
        CONST char *varValue;

        varValue = Tcl_GetVar2(interp, "env", "TZ", TCL_GLOBAL_ONLY);
        if (varValue != NULL) {
	    savedTZEnv = strcpy(ckalloc(strlen(varValue) + 1), varValue);
        } else {
            savedTZEnv = NULL;
	}
        Tcl_SetVar2(interp, "env", "TZ", "GMT", TCL_GLOBAL_ONLY);
        savedTimeZone = timezone;
        timezone = 0;
        tzset();
    }
#endif

    tclockVal = clockVal;
    timeDataPtr = TclpGetDate((TclpTime_t) &tclockVal, useGMT);
    
    /*
     * Make a guess at the upper limit on the substituted string size
     * based on the number of percents in the string.
     */

    for (bufSize = 1, p = format; *p != '\0'; p++) {
	if (*p == '%') {







|


















|







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
     * This is a kludge for systems not having the timezone string in
     * struct tm.  No matter what was specified, they use the local
     * timezone string.  Since this kludge requires fiddling with the
     * TZ environment variable, it will mess up if done on multiple
     * threads at once.  Protect it with a the clock mutex.
     */

    Tcl_MutexLock(&clockMutex);
    if (useGMT) {
        CONST char *varValue;

        varValue = Tcl_GetVar2(interp, "env", "TZ", TCL_GLOBAL_ONLY);
        if (varValue != NULL) {
	    savedTZEnv = strcpy(ckalloc(strlen(varValue) + 1), varValue);
        } else {
            savedTZEnv = NULL;
	}
        Tcl_SetVar2(interp, "env", "TZ", "GMT", TCL_GLOBAL_ONLY);
        savedTimeZone = timezone;
        timezone = 0;
        tzset();
    }
#endif

    tclockVal = clockVal;
    timeDataPtr = TclpGetDate((TclpTime_t) &tclockVal, useGMT);

    /*
     * Make a guess at the upper limit on the substituted string size
     * based on the number of percents in the string.
     */

    for (bufSize = 1, p = format; *p != '\0'; p++) {
	if (*p == '%') {
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
    Tcl_DStringSetLength(&buffer, bufSize);

    /* If we haven't locked the clock mutex up above, lock it now. */

#if defined(HAVE_TM_ZONE) || defined(WIN32)
    Tcl_MutexLock(&clockMutex);
#endif
    result = TclpStrftime( buffer.string, (unsigned int) bufSize,
			   format, timeDataPtr, useGMT);
#if defined(HAVE_TM_ZONE) || defined(WIN32)
    Tcl_MutexUnlock(&clockMutex);
#endif

#if !defined(HAVE_TM_ZONE) && !defined(WIN32)
    if (useGMT) {
        if (savedTZEnv != NULL) {
            Tcl_SetVar2(interp, "env", "TZ", savedTZEnv, TCL_GLOBAL_ONLY);
            ckfree(savedTZEnv);
        } else {
            Tcl_UnsetVar2(interp, "env", "TZ", TCL_GLOBAL_ONLY);
        }
        timezone = savedTimeZone;
        tzset();
    }
    Tcl_MutexUnlock( &clockMutex );
#endif

    if (result == 0) {
	/*
	 * A zero return is the error case (can also mean the strftime
	 * didn't get enough space to write into).  We know it doesn't
	 * mean that we wrote zero chars because the check for an empty
	 * format string is above.
	 */
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		"bad format string \"", format, "\"", (char *) NULL);
	return TCL_ERROR;
    }

    Tcl_SetStringObj(Tcl_GetObjResult(interp), buffer.string, -1);

    Tcl_DStringFree(&buffer);
    return TCL_OK;
}








|
|















|



















<
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

    Tcl_DStringSetLength(&buffer, bufSize);

    /* If we haven't locked the clock mutex up above, lock it now. */

#if defined(HAVE_TM_ZONE) || defined(WIN32)
    Tcl_MutexLock(&clockMutex);
#endif
    result = TclpStrftime(buffer.string, (unsigned int) bufSize, format,
	    timeDataPtr, useGMT);
#if defined(HAVE_TM_ZONE) || defined(WIN32)
    Tcl_MutexUnlock(&clockMutex);
#endif

#if !defined(HAVE_TM_ZONE) && !defined(WIN32)
    if (useGMT) {
        if (savedTZEnv != NULL) {
            Tcl_SetVar2(interp, "env", "TZ", savedTZEnv, TCL_GLOBAL_ONLY);
            ckfree(savedTZEnv);
        } else {
            Tcl_UnsetVar2(interp, "env", "TZ", TCL_GLOBAL_ONLY);
        }
        timezone = savedTimeZone;
        tzset();
    }
    Tcl_MutexUnlock(&clockMutex);
#endif

    if (result == 0) {
	/*
	 * A zero return is the error case (can also mean the strftime
	 * didn't get enough space to write into).  We know it doesn't
	 * mean that we wrote zero chars because the check for an empty
	 * format string is above.
	 */
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		"bad format string \"", format, "\"", (char *) NULL);
	return TCL_ERROR;
    }

    Tcl_SetStringObj(Tcl_GetObjResult(interp), buffer.string, -1);

    Tcl_DStringFree(&buffer);
    return TCL_OK;
}

Changes to generic/tclCmdAH.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/* 
 * tclCmdAH.c --
 *
 *	This file contains the top-level command routines for most of
 *	the Tcl built-in commands whose names begin with the letters
 *	A to H.
 *
 * Copyright (c) 1987-1993 The Regents of the University of California.
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclCmdAH.c,v 1.33.2.1 2003/09/05 23:08:06 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include <locale.h>

/*
 * Prototypes for local procedures defined in this file:
 */

static int		CheckAccess _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *objPtr, int mode));
static int		GetStatBuf _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *objPtr, Tcl_FSStatProc *statProc,
			    Tcl_StatBuf *statPtr));
static char *		GetTypeFromMode _ANSI_ARGS_((int mode));
static int		StoreStatData _ANSI_ARGS_((Tcl_Interp *interp,
			    char *varName, Tcl_StatBuf *statPtr));

/*
 *----------------------------------------------------------------------
 *
 * Tcl_BreakObjCmd --
 *
 *	This procedure is invoked to process the "break" Tcl command.













|











|

|



|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/* 
 * tclCmdAH.c --
 *
 *	This file contains the top-level command routines for most of
 *	the Tcl built-in commands whose names begin with the letters
 *	A to H.
 *
 * Copyright (c) 1987-1993 The Regents of the University of California.
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclCmdAH.c,v 1.33.2.2 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include <locale.h>

/*
 * Prototypes for local procedures defined in this file:
 */

static int		CheckAccess _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *pathPtr, int mode));
static int		GetStatBuf _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *pathPtr, Tcl_FSStatProc *statProc,
			    Tcl_StatBuf *statPtr));
static char *		GetTypeFromMode _ANSI_ARGS_((int mode));
static int		StoreStatData _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *varName, Tcl_StatBuf *statPtr));

/*
 *----------------------------------------------------------------------
 *
 * Tcl_BreakObjCmd --
 *
 *	This procedure is invoked to process the "break" Tcl command.
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
	"pathtype",	"readable",	"readlink",	"rename",
	"rootname",	"separator",    "size",		"split",	
	"stat",         "system", 
	"tail",		"type",		"volumes",	"writable",
	(char *) NULL
    };
    enum options {
	FILE_ATIME,	FILE_ATTRIBUTES, FILE_CHANNELS,	FILE_COPY,
	FILE_DELETE,
	FILE_DIRNAME,	FILE_EXECUTABLE, FILE_EXISTS,	FILE_EXTENSION,
	FILE_ISDIRECTORY, FILE_ISFILE,	FILE_JOIN,	FILE_LINK, 
	FILE_LSTAT,     FILE_MTIME,	FILE_MKDIR,	FILE_NATIVENAME, 
	FILE_NORMALIZE, FILE_OWNED,
	FILE_PATHTYPE,	FILE_READABLE,	FILE_READLINK,	FILE_RENAME,
	FILE_ROOTNAME,	FILE_SEPARATOR, FILE_SIZE,	FILE_SPLIT,	
	FILE_STAT,      FILE_SYSTEM, 
	FILE_TAIL,	FILE_TYPE,	FILE_VOLUMES,	FILE_WRITABLE
    };

    if (objc < 2) {
    	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
        return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[1], fileOptions, "option", 0,
	    &index) != TCL_OK) {
    	return TCL_ERROR;
    }

    switch ((enum options) index) {
    	case FILE_ATIME: {
	    Tcl_StatBuf buf;
	    struct utimbuf tval;

	    if ((objc < 3) || (objc > 4)) {
		Tcl_WrongNumArgs(interp, 2, objv, "name ?time?");
		return TCL_ERROR;
	    }







|
|
|
|
|
|
|
|
|
|












|







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
	"pathtype",	"readable",	"readlink",	"rename",
	"rootname",	"separator",    "size",		"split",	
	"stat",         "system", 
	"tail",		"type",		"volumes",	"writable",
	(char *) NULL
    };
    enum options {
	FCMD_ATIME,	FCMD_ATTRIBUTES, FCMD_CHANNELS,	FCMD_COPY,
	FCMD_DELETE,
	FCMD_DIRNAME,	FCMD_EXECUTABLE, FCMD_EXISTS,	FCMD_EXTENSION,
	FCMD_ISDIRECTORY, FCMD_ISFILE,	FCMD_JOIN,	FCMD_LINK, 
	FCMD_LSTAT,     FCMD_MTIME,	FCMD_MKDIR,	FCMD_NATIVENAME, 
	FCMD_NORMALIZE, FCMD_OWNED,
	FCMD_PATHTYPE,	FCMD_READABLE,	FCMD_READLINK,	FCMD_RENAME,
	FCMD_ROOTNAME,	FCMD_SEPARATOR, FCMD_SIZE,	FCMD_SPLIT,	
	FCMD_STAT,      FCMD_SYSTEM, 
	FCMD_TAIL,	FCMD_TYPE,	FCMD_VOLUMES,	FCMD_WRITABLE
    };

    if (objc < 2) {
    	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
        return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[1], fileOptions, "option", 0,
	    &index) != TCL_OK) {
    	return TCL_ERROR;
    }

    switch ((enum options) index) {
    	case FCMD_ATIME: {
	    Tcl_StatBuf buf;
	    struct utimbuf tval;

	    if ((objc < 3) || (objc > 4)) {
		Tcl_WrongNumArgs(interp, 2, objv, "name ?time?");
		return TCL_ERROR;
	    }
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
		if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) {
		    return TCL_ERROR;
		}
	    }
	    Tcl_SetLongObj(Tcl_GetObjResult(interp), (long) buf.st_atime);
	    return TCL_OK;
	}
	case FILE_ATTRIBUTES: {
            return TclFileAttrsCmd(interp, objc, objv);
	}
	case FILE_CHANNELS: {
	    if ((objc < 2) || (objc > 3)) {
		Tcl_WrongNumArgs(interp, 2, objv, "?pattern?");
		return TCL_ERROR;
	    }
	    return Tcl_GetChannelNamesEx(interp,
		    ((objc == 2) ? NULL : Tcl_GetString(objv[2])));
	}
	case FILE_COPY: {
	    return TclFileCopyCmd(interp, objc, objv);
	}	    
	case FILE_DELETE: {
	    return TclFileDeleteCmd(interp, objc, objv);
	}
    	case FILE_DIRNAME: {
	    Tcl_Obj *dirPtr;

	    if (objc != 3) {
		goto only3Args;
	    }
	    dirPtr = TclFileDirname(interp, objv[2]);
	    if (dirPtr == NULL) {
	        return TCL_ERROR;
	    } else {
		Tcl_SetObjResult(interp, dirPtr);
		Tcl_DecrRefCount(dirPtr);
		return TCL_OK;
	    }
	}
	case FILE_EXECUTABLE: {
	    if (objc != 3) {
		goto only3Args;
	    }
	    return CheckAccess(interp, objv[2], X_OK);
	}
	case FILE_EXISTS: {
	    if (objc != 3) {
		goto only3Args;
	    }
	    return CheckAccess(interp, objv[2], F_OK);


	}
	case FILE_EXTENSION: {
	    char *fileName, *extension;
	    if (objc != 3) {
	    	goto only3Args;
	    }
	    fileName = Tcl_GetString(objv[2]);
	    extension = TclGetExtension(fileName);
	    if (extension != NULL) {
	    	Tcl_SetStringObj(Tcl_GetObjResult(interp), extension, -1);


	    }
	    return TCL_OK;
	}

    	case FILE_ISDIRECTORY: {
	    int value;
	    Tcl_StatBuf buf;

	    if (objc != 3) {
		goto only3Args;
	    }
	    value = 0;
	    if (GetStatBuf(NULL, objv[2], Tcl_FSStat, &buf) == TCL_OK) {
		value = S_ISDIR(buf.st_mode);
	    }
	    Tcl_SetBooleanObj(Tcl_GetObjResult(interp), value);
	    return TCL_OK;
	}
    	case FILE_ISFILE: {
	    int value;
	    Tcl_StatBuf buf;
	    
    	    if (objc != 3) {
    	    	goto only3Args;
    	    }
	    value = 0;
	    if (GetStatBuf(NULL, objv[2], Tcl_FSStat, &buf) == TCL_OK) {
		value = S_ISREG(buf.st_mode);
	    }
	    Tcl_SetBooleanObj(Tcl_GetObjResult(interp), value);
	    return TCL_OK;
	}
	case FILE_JOIN: {
	    Tcl_Obj *resObj;

	    if (objc < 3) {
		Tcl_WrongNumArgs(interp, 2, objv, "name ?name ...?");
		return TCL_ERROR;
	    }
	    resObj = Tcl_FSJoinToPath(NULL, objc - 2, objv + 2);
	    Tcl_SetObjResult(interp, resObj);
	    return TCL_OK;
	}
	case FILE_LINK: {
	    Tcl_Obj *contents;
	    int index;
	    
	    if (objc < 3 || objc > 5) {
		Tcl_WrongNumArgs(interp, 2, objv, 
				 "?-linktype? linkname ?target?");
		return TCL_ERROR;







|

<
|






<
|

<
|

<
|

>



|








|




<
|




>
>
|
<
<



|
<
|
|
>
>
|
|
|
>
|













|













|










|







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
		if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) {
		    return TCL_ERROR;
		}
	    }
	    Tcl_SetLongObj(Tcl_GetObjResult(interp), (long) buf.st_atime);
	    return TCL_OK;
	}
	case FCMD_ATTRIBUTES:
            return TclFileAttrsCmd(interp, objc, objv);

	case FCMD_CHANNELS:
	    if ((objc < 2) || (objc > 3)) {
		Tcl_WrongNumArgs(interp, 2, objv, "?pattern?");
		return TCL_ERROR;
	    }
	    return Tcl_GetChannelNamesEx(interp,
		    ((objc == 2) ? NULL : Tcl_GetString(objv[2])));

	case FCMD_COPY:
	    return TclFileCopyCmd(interp, objc, objv);

	case FCMD_DELETE:
	    return TclFileDeleteCmd(interp, objc, objv);

    	case FCMD_DIRNAME: {
	    Tcl_Obj *dirPtr;

	    if (objc != 3) {
		goto only3Args;
	    }
	    dirPtr = TclPathPart(interp, objv[2], TCL_PATH_DIRNAME);
	    if (dirPtr == NULL) {
	        return TCL_ERROR;
	    } else {
		Tcl_SetObjResult(interp, dirPtr);
		Tcl_DecrRefCount(dirPtr);
		return TCL_OK;
	    }
	}
	case FCMD_EXECUTABLE:
	    if (objc != 3) {
		goto only3Args;
	    }
	    return CheckAccess(interp, objv[2], X_OK);

	case FCMD_EXISTS:
	    if (objc != 3) {
		goto only3Args;
	    }
	    return CheckAccess(interp, objv[2], F_OK);
	case FCMD_EXTENSION: {
	    Tcl_Obj *ext;
	    


	    if (objc != 3) {
	    	goto only3Args;
	    }
	    ext = TclPathPart(interp, objv[2], TCL_PATH_EXTENSION);

	    if (ext != NULL) {
	        Tcl_SetObjResult(interp, ext);
		Tcl_DecrRefCount(ext);
		return TCL_OK;
	    } else {
		return TCL_ERROR;
	    }
	}
    	case FCMD_ISDIRECTORY: {
	    int value;
	    Tcl_StatBuf buf;

	    if (objc != 3) {
		goto only3Args;
	    }
	    value = 0;
	    if (GetStatBuf(NULL, objv[2], Tcl_FSStat, &buf) == TCL_OK) {
		value = S_ISDIR(buf.st_mode);
	    }
	    Tcl_SetBooleanObj(Tcl_GetObjResult(interp), value);
	    return TCL_OK;
	}
    	case FCMD_ISFILE: {
	    int value;
	    Tcl_StatBuf buf;
	    
    	    if (objc != 3) {
    	    	goto only3Args;
    	    }
	    value = 0;
	    if (GetStatBuf(NULL, objv[2], Tcl_FSStat, &buf) == TCL_OK) {
		value = S_ISREG(buf.st_mode);
	    }
	    Tcl_SetBooleanObj(Tcl_GetObjResult(interp), value);
	    return TCL_OK;
	}
	case FCMD_JOIN: {
	    Tcl_Obj *resObj;

	    if (objc < 3) {
		Tcl_WrongNumArgs(interp, 2, objv, "name ?name ...?");
		return TCL_ERROR;
	    }
	    resObj = Tcl_FSJoinToPath(NULL, objc - 2, objv + 2);
	    Tcl_SetObjResult(interp, resObj);
	    return TCL_OK;
	}
	case FCMD_LINK: {
	    Tcl_Obj *contents;
	    int index;
	    
	    if (objc < 3 || objc > 5) {
		Tcl_WrongNumArgs(interp, 2, objv, 
				 "?-linktype? linkname ?target?");
		return TCL_ERROR;
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
		if (Tcl_FSConvertToPathType(interp, objv[index]) != TCL_OK) {
		    return TCL_ERROR;
		}
		/* Create link from source to target */
		contents = Tcl_FSLink(objv[index], objv[index+1], linkAction);
		if (contents == NULL) {
		    /* 
		     * We handle two common error cases specially, and
		     * for all other errors, we use the standard posix
		     * error message.
		     */
		    if (errno == EEXIST) {
			Tcl_AppendResult(interp, "could not create new link \"", 
				Tcl_GetString(objv[index]), 
				"\": that path already exists", (char *) NULL);
		    } else if (errno == ENOENT) {













			Tcl_AppendResult(interp, "could not create new link \"", 

				Tcl_GetString(objv[index]), 






				"\" since target \"", 
				Tcl_GetString(objv[index+1]), 
				"\" doesn't exist", 
				(char *) NULL);

		    } else {
			Tcl_AppendResult(interp, "could not create new link \"", 
				Tcl_GetString(objv[index]), "\" pointing to \"", 
				Tcl_GetString(objv[index+1]), "\": ", 
				Tcl_PosixError(interp), (char *) NULL);
		    }
		    return TCL_ERROR;







|








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







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
		if (Tcl_FSConvertToPathType(interp, objv[index]) != TCL_OK) {
		    return TCL_ERROR;
		}
		/* Create link from source to target */
		contents = Tcl_FSLink(objv[index], objv[index+1], linkAction);
		if (contents == NULL) {
		    /* 
		     * We handle three common error cases specially, and
		     * for all other errors, we use the standard posix
		     * error message.
		     */
		    if (errno == EEXIST) {
			Tcl_AppendResult(interp, "could not create new link \"", 
				Tcl_GetString(objv[index]), 
				"\": that path already exists", (char *) 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 \"", 
				    Tcl_GetString(objv[index]), 
				    "\": no such file or directory", 
				    (char *) NULL);
			} else {
			    Tcl_AppendResult(interp, 
			            "could not create new link \"", 
				    Tcl_GetString(objv[index]), 
				    "\": target \"", 
				    Tcl_GetString(objv[index+1]), 
				    "\" doesn't exist", 
				    (char *) NULL);
			}
		    } else {
			Tcl_AppendResult(interp, "could not create new link \"", 
				Tcl_GetString(objv[index]), "\" pointing to \"", 
				Tcl_GetString(objv[index+1]), "\": ", 
				Tcl_PosixError(interp), (char *) NULL);
		    }
		    return TCL_ERROR;
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
		 * result refCount.  If we are creating a link, this
		 * will just be objv[index+1], and so we don't own it.
		 */
		Tcl_DecrRefCount(contents);
	    }
	    return TCL_OK;
	}
    	case FILE_LSTAT: {
	    char *varName;
	    Tcl_StatBuf buf;

    	    if (objc != 4) {
    	    	Tcl_WrongNumArgs(interp, 2, objv, "name varName");
    	    	return TCL_ERROR;
    	    }
	    if (GetStatBuf(interp, objv[2], Tcl_FSLstat, &buf) != TCL_OK) {
		return TCL_ERROR;
	    }
	    varName = Tcl_GetString(objv[3]);
	    return StoreStatData(interp, varName, &buf);
	}
	case FILE_MTIME: {
	    Tcl_StatBuf buf;
	    struct utimbuf tval;

	    if ((objc < 3) || (objc > 4)) {
		Tcl_WrongNumArgs(interp, 2, objv, "name ?time?");
		return TCL_ERROR;
	    }







|
<









<
|

|







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
		 * result refCount.  If we are creating a link, this
		 * will just be objv[index+1], and so we don't own it.
		 */
		Tcl_DecrRefCount(contents);
	    }
	    return TCL_OK;
	}
    	case FCMD_LSTAT: {

	    Tcl_StatBuf buf;

    	    if (objc != 4) {
    	    	Tcl_WrongNumArgs(interp, 2, objv, "name varName");
    	    	return TCL_ERROR;
    	    }
	    if (GetStatBuf(interp, objv[2], Tcl_FSLstat, &buf) != TCL_OK) {
		return TCL_ERROR;
	    }

	    return StoreStatData(interp, objv[3], &buf);
	}
	case FCMD_MTIME: {
	    Tcl_StatBuf buf;
	    struct utimbuf tval;

	    if ((objc < 3) || (objc > 4)) {
		Tcl_WrongNumArgs(interp, 2, objv, "name ?time?");
		return TCL_ERROR;
	    }
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
		if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) {
		    return TCL_ERROR;
		}
	    }
	    Tcl_SetLongObj(Tcl_GetObjResult(interp), (long) buf.st_mtime);
	    return TCL_OK;
	}
	case FILE_MKDIR: {
	    if (objc < 3) {
		Tcl_WrongNumArgs(interp, 2, objv, "name ?name ...?");
		return TCL_ERROR;
	    }
	    return TclFileMakeDirsCmd(interp, objc, objv);
	}
	case FILE_NATIVENAME: {
	    CONST char *fileName;
	    Tcl_DString ds;

	    if (objc != 3) {
		goto only3Args;
	    }
	    fileName = Tcl_GetString(objv[2]);
	    fileName = Tcl_TranslateFileName(interp, fileName, &ds);
	    if (fileName == NULL) {
		return TCL_ERROR;
	    }
	    Tcl_SetStringObj(Tcl_GetObjResult(interp), fileName, 
			     Tcl_DStringLength(&ds));
	    Tcl_DStringFree(&ds);
	    return TCL_OK;
	}
	case FILE_NORMALIZE: {
	    Tcl_Obj *fileName;

	    if (objc != 3) {
		Tcl_WrongNumArgs(interp, 2, objv, "filename");
		return TCL_ERROR;
	    }

	    fileName = Tcl_FSGetNormalizedPath(interp, objv[2]);



	    Tcl_SetObjResult(interp, fileName);
	    return TCL_OK;
	}
	case FILE_OWNED: {
	    int value;
	    Tcl_StatBuf buf;
	    
	    if (objc != 3) {
		goto only3Args;
	    }
	    value = 0;







|





<
|
















|








>
>
>



|







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
		if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) {
		    return TCL_ERROR;
		}
	    }
	    Tcl_SetLongObj(Tcl_GetObjResult(interp), (long) buf.st_mtime);
	    return TCL_OK;
	}
	case FCMD_MKDIR:
	    if (objc < 3) {
		Tcl_WrongNumArgs(interp, 2, objv, "name ?name ...?");
		return TCL_ERROR;
	    }
	    return TclFileMakeDirsCmd(interp, objc, objv);

	case FCMD_NATIVENAME: {
	    CONST char *fileName;
	    Tcl_DString ds;

	    if (objc != 3) {
		goto only3Args;
	    }
	    fileName = Tcl_GetString(objv[2]);
	    fileName = Tcl_TranslateFileName(interp, fileName, &ds);
	    if (fileName == NULL) {
		return TCL_ERROR;
	    }
	    Tcl_SetStringObj(Tcl_GetObjResult(interp), fileName, 
			     Tcl_DStringLength(&ds));
	    Tcl_DStringFree(&ds);
	    return TCL_OK;
	}
	case FCMD_NORMALIZE: {
	    Tcl_Obj *fileName;

	    if (objc != 3) {
		Tcl_WrongNumArgs(interp, 2, objv, "filename");
		return TCL_ERROR;
	    }

	    fileName = Tcl_FSGetNormalizedPath(interp, objv[2]);
	    if (fileName == NULL) {
	        return TCL_ERROR;
	    }
	    Tcl_SetObjResult(interp, fileName);
	    return TCL_OK;
	}
	case FCMD_OWNED: {
	    int value;
	    Tcl_StatBuf buf;
	    
	    if (objc != 3) {
		goto only3Args;
	    }
	    value = 0;
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
#else
		value = (geteuid() == buf.st_uid);
#endif
	    }	    
	    Tcl_SetBooleanObj(Tcl_GetObjResult(interp), value);
	    return TCL_OK;
	}
	case FILE_PATHTYPE: {
	    if (objc != 3) {
		goto only3Args;
	    }
	    switch (Tcl_FSGetPathType(objv[2])) {
	    	case TCL_PATH_ABSOLUTE:
	    	    Tcl_SetStringObj(Tcl_GetObjResult(interp), "absolute", -1);
		    break;
	    	case TCL_PATH_RELATIVE:
	    	    Tcl_SetStringObj(Tcl_GetObjResult(interp), "relative", -1);
	    	    break;
	    	case TCL_PATH_VOLUME_RELATIVE:
		    Tcl_SetStringObj(Tcl_GetObjResult(interp), 
				     "volumerelative", -1);
		    break;
	    }
	    return TCL_OK;
	}
    	case FILE_READABLE: {
	    if (objc != 3) {
		goto only3Args;
	    }
	    return CheckAccess(interp, objv[2], R_OK);
	}
	case FILE_READLINK: {
	    Tcl_Obj *contents;
		
	    if (objc != 3) {
		goto only3Args;
	    }
	    
	    if (Tcl_FSConvertToPathType(interp, objv[2]) != TCL_OK) {







|




|
|
|
|
|
|
|
|
|
|


<
|




<
|







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
#else
		value = (geteuid() == buf.st_uid);
#endif
	    }	    
	    Tcl_SetBooleanObj(Tcl_GetObjResult(interp), value);
	    return TCL_OK;
	}
	case FCMD_PATHTYPE:
	    if (objc != 3) {
		goto only3Args;
	    }
	    switch (Tcl_FSGetPathType(objv[2])) {
	    case TCL_PATH_ABSOLUTE:
		Tcl_SetStringObj(Tcl_GetObjResult(interp), "absolute", -1);
		break;
	    case TCL_PATH_RELATIVE:
		Tcl_SetStringObj(Tcl_GetObjResult(interp), "relative", -1);
		break;
	    case TCL_PATH_VOLUME_RELATIVE:
		Tcl_SetStringObj(Tcl_GetObjResult(interp), "volumerelative",
			-1);
		break;
	    }
	    return TCL_OK;

    	case FCMD_READABLE:
	    if (objc != 3) {
		goto only3Args;
	    }
	    return CheckAccess(interp, objv[2], R_OK);

	case FCMD_READLINK: {
	    Tcl_Obj *contents;
		
	    if (objc != 3) {
		goto only3Args;
	    }
	    
	    if (Tcl_FSConvertToPathType(interp, objv[2]) != TCL_OK) {
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
	    		Tcl_PosixError(interp), (char *) NULL);
	    	return TCL_ERROR;
	    }
	    Tcl_SetObjResult(interp, contents);
	    Tcl_DecrRefCount(contents);
	    return TCL_OK;
	}
	case FILE_RENAME: {
	    return TclFileRenameCmd(interp, objc, objv);
	}
	case FILE_ROOTNAME: {
	    int length;
	    char *fileName, *extension;
	    
	    if (objc != 3) {
		goto only3Args;
	    }
	    fileName = Tcl_GetStringFromObj(objv[2], &length);
	    extension = TclGetExtension(fileName);
	    if (extension == NULL) {
	    	Tcl_SetObjResult(interp, objv[2]);


	    } else {
	        Tcl_SetStringObj(Tcl_GetObjResult(interp), fileName,
			(int) (length - strlen(extension)));
	    }
	    return TCL_OK;
	}
	case FILE_SEPARATOR: {
	    if ((objc < 2) || (objc > 3)) {
		Tcl_WrongNumArgs(interp, 2, objv, "?name?");
		return TCL_ERROR;
	    }
	    if (objc == 2) {
	        char *separator = NULL; /* lint */
		switch (tclPlatform) {
		    case TCL_PLATFORM_UNIX:
			separator = "/";
			break;
		    case TCL_PLATFORM_WINDOWS:
			separator = "\\";
			break;
		    case TCL_PLATFORM_MAC:
			separator = ":";
			break;
		}
		Tcl_SetObjResult(interp, Tcl_NewStringObj(separator,1));
	    } else {
		Tcl_Obj *separatorObj = Tcl_FSPathSeparator(objv[2]);
		if (separatorObj != NULL) {
		    Tcl_SetObjResult(interp, separatorObj);
		} else {
		    Tcl_SetObjResult(interp, 
			    Tcl_NewStringObj("Unrecognised path",-1));
		    return TCL_ERROR;
		}
	    }
	    return TCL_OK;
	}
	case FILE_SIZE: {
	    Tcl_StatBuf buf;
	    
	    if (objc != 3) {
		goto only3Args;
	    }
	    if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) {
		return TCL_ERROR;
	    }
	    Tcl_SetWideIntObj(Tcl_GetObjResult(interp),
		    (Tcl_WideInt) buf.st_size);
	    return TCL_OK;
	}
	case FILE_SPLIT: {


	    if (objc != 3) {
		goto only3Args;
	    }










	    Tcl_SetObjResult(interp, Tcl_FSSplitPath(objv[2], NULL));
	    return TCL_OK;
	}

	case FILE_STAT: {
	    char *varName;
	    Tcl_StatBuf buf;
	    
	    if (objc != 4) {
	    	Tcl_WrongNumArgs(interp, 1, objv, "stat name varName");
		return TCL_ERROR;
	    }
	    if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) {
		return TCL_ERROR;
	    }
	    varName = Tcl_GetString(objv[3]);
	    return StoreStatData(interp, varName, &buf);
	}
	case FILE_SYSTEM: {
	    Tcl_Obj* fsInfo;

	    if (objc != 3) {
		goto only3Args;
	    }
	    fsInfo = Tcl_FSFileSystemInfo(objv[2]);
	    if (fsInfo != NULL) {
		Tcl_SetObjResult(interp, fsInfo);
		return TCL_OK;
	    } else {
		Tcl_SetObjResult(interp, 
				 Tcl_NewStringObj("Unrecognised path",-1));
		return TCL_ERROR;
	    }
	}
    	case FILE_TAIL: {
	    int splitElements;
	    Tcl_Obj *splitPtr;

	    if (objc != 3) {
		goto only3Args;
	    }
	    /* 
	     * The behaviour we want here is slightly different to
	     * the standard Tcl_FSSplitPath in the handling of home
	     * directories; Tcl_FSSplitPath preserves the "~" while 
	     * this code computes the actual full path name, if we
	     * had just a single component.
	     */	    
	    splitPtr = Tcl_FSSplitPath(objv[2], &splitElements);
	    if ((splitElements == 1) && (Tcl_GetString(objv[2])[0] == '~')) {
		Tcl_DecrRefCount(splitPtr);
		splitPtr = Tcl_FSGetNormalizedPath(interp, objv[2]);
		if (splitPtr == NULL) {
		    return TCL_ERROR;
		}
		splitPtr = Tcl_FSSplitPath(splitPtr, &splitElements);
	    }

	    /*
	     * Return the last component, unless it is the only component,
	     * and it is the root of an absolute path.
	     */

	    if (splitElements > 0) {
	    	if ((splitElements > 1)
		  || (Tcl_FSGetPathType(objv[2]) == TCL_PATH_RELATIVE)) {
		    
		    Tcl_Obj *tail = NULL;
		    Tcl_ListObjIndex(NULL, splitPtr, splitElements-1, &tail);
		    Tcl_SetObjResult(interp, tail);
	    	}
	    }
	    Tcl_DecrRefCount(splitPtr);
	    return TCL_OK;
	}

	case FILE_TYPE: {
	    Tcl_StatBuf buf;

	    if (objc != 3) {
	    	goto only3Args;
	    }
	    if (GetStatBuf(interp, objv[2], Tcl_FSLstat, &buf) != TCL_OK) {
		return TCL_ERROR;
	    }
	    Tcl_SetStringObj(Tcl_GetObjResult(interp), 
		    GetTypeFromMode((unsigned short) buf.st_mode), -1);
	    return TCL_OK;
	}
	case FILE_VOLUMES: {
	    if (objc != 2) {
		Tcl_WrongNumArgs(interp, 2, objv, NULL);
		return TCL_ERROR;
	    }
	    Tcl_SetObjResult(interp, Tcl_FSListVolumes());
	    return TCL_OK;
	}
	case FILE_WRITABLE: {
	    if (objc != 3) {
	    	goto only3Args;
	    }
	    return CheckAccess(interp, objv[2], W_OK);
	}
    }

    only3Args:
    Tcl_WrongNumArgs(interp, 2, objv, "name");
    return TCL_ERROR;
}








|

<
|
<
|




|
<
|
|
>
>

<
|

<

|







|
|
|
|
|
|
|
|
|













<
|












|
>
>



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









<
|

|

>













|
<
|




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












|






<
|




<







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
	    		Tcl_PosixError(interp), (char *) NULL);
	    	return TCL_ERROR;
	    }
	    Tcl_SetObjResult(interp, contents);
	    Tcl_DecrRefCount(contents);
	    return TCL_OK;
	}
	case FCMD_RENAME:
	    return TclFileRenameCmd(interp, objc, objv);

	case FCMD_ROOTNAME: {

	    Tcl_Obj *root;
	    
	    if (objc != 3) {
		goto only3Args;
	    }
	    root = TclPathPart(interp, objv[2], TCL_PATH_ROOT);

	    if (root != NULL) {
		Tcl_SetObjResult(interp, root);
		Tcl_DecrRefCount(root);
		return TCL_OK;
	    } else {

		return TCL_ERROR;
	    }

	}
	case FCMD_SEPARATOR:
	    if ((objc < 2) || (objc > 3)) {
		Tcl_WrongNumArgs(interp, 2, objv, "?name?");
		return TCL_ERROR;
	    }
	    if (objc == 2) {
	        char *separator = NULL; /* lint */
		switch (tclPlatform) {
		case TCL_PLATFORM_UNIX:
		    separator = "/";
		    break;
		case TCL_PLATFORM_WINDOWS:
		    separator = "\\";
		    break;
		case TCL_PLATFORM_MAC:
		    separator = ":";
		    break;
		}
		Tcl_SetObjResult(interp, Tcl_NewStringObj(separator,1));
	    } else {
		Tcl_Obj *separatorObj = Tcl_FSPathSeparator(objv[2]);
		if (separatorObj != NULL) {
		    Tcl_SetObjResult(interp, separatorObj);
		} else {
		    Tcl_SetObjResult(interp, 
			    Tcl_NewStringObj("Unrecognised path",-1));
		    return TCL_ERROR;
		}
	    }
	    return TCL_OK;

	case FCMD_SIZE: {
	    Tcl_StatBuf buf;
	    
	    if (objc != 3) {
		goto only3Args;
	    }
	    if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) {
		return TCL_ERROR;
	    }
	    Tcl_SetWideIntObj(Tcl_GetObjResult(interp),
		    (Tcl_WideInt) buf.st_size);
	    return TCL_OK;
	}
	case FCMD_SPLIT: {
	    Tcl_Obj *res;
	    
	    if (objc != 3) {
		goto only3Args;
	    }
	    res = Tcl_FSSplitPath(objv[2], NULL);
	    if (res == NULL) {
		if (interp != NULL) {
		    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), 
			"could not read \"", Tcl_GetString(objv[2]),
			"\": no such file or directory", 
			(char *) NULL);
		}
		return TCL_ERROR;
	    } else {
		Tcl_SetObjResult(interp, res);
		return TCL_OK;
	    }
	}
	case FCMD_STAT: {

	    Tcl_StatBuf buf;
	    
	    if (objc != 4) {
	    	Tcl_WrongNumArgs(interp, 1, objv, "stat name varName");
		return TCL_ERROR;
	    }
	    if (GetStatBuf(interp, objv[2], Tcl_FSStat, &buf) != TCL_OK) {
		return TCL_ERROR;
	    }

	    return StoreStatData(interp, objv[3], &buf);
	}
	case FCMD_SYSTEM: {
	    Tcl_Obj* fsInfo;

	    if (objc != 3) {
		goto only3Args;
	    }
	    fsInfo = Tcl_FSFileSystemInfo(objv[2]);
	    if (fsInfo != NULL) {
		Tcl_SetObjResult(interp, fsInfo);
		return TCL_OK;
	    } else {
		Tcl_SetObjResult(interp, 
				 Tcl_NewStringObj("Unrecognised path",-1));
		return TCL_ERROR;
	    }
	}
    	case FCMD_TAIL: {

	    Tcl_Obj *dirPtr;

	    if (objc != 3) {
		goto only3Args;
	    }










	    dirPtr = TclPathPart(interp, objv[2], TCL_PATH_TAIL);
	    if (dirPtr == NULL) {
		return TCL_ERROR;



	    } else {











		Tcl_SetObjResult(interp, dirPtr);


		Tcl_DecrRefCount(dirPtr);
		return TCL_OK;
	    }
	}
	case FCMD_TYPE: {
	    Tcl_StatBuf buf;

	    if (objc != 3) {
	    	goto only3Args;
	    }
	    if (GetStatBuf(interp, objv[2], Tcl_FSLstat, &buf) != TCL_OK) {
		return TCL_ERROR;
	    }
	    Tcl_SetStringObj(Tcl_GetObjResult(interp), 
		    GetTypeFromMode((unsigned short) buf.st_mode), -1);
	    return TCL_OK;
	}
	case FCMD_VOLUMES:
	    if (objc != 2) {
		Tcl_WrongNumArgs(interp, 2, objv, NULL);
		return TCL_ERROR;
	    }
	    Tcl_SetObjResult(interp, Tcl_FSListVolumes());
	    return TCL_OK;

	case FCMD_WRITABLE:
	    if (objc != 3) {
	    	goto only3Args;
	    }
	    return CheckAccess(interp, objv[2], W_OK);

    }

    only3Args:
    Tcl_WrongNumArgs(interp, 2, objv, "name");
    return TCL_ERROR;
}

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
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
  
static int
CheckAccess(interp, objPtr, mode)
    Tcl_Interp *interp;		/* Interp for status return.  Must not be
				 * NULL. */
    Tcl_Obj *objPtr;		/* Name of file to check. */
    int mode;			/* Attribute to check; passed as argument to
				 * access(). */
{
    int value;
    
    if (Tcl_FSConvertToPathType(interp, objPtr) != TCL_OK) {
	value = 0;
    } else {
	value = (Tcl_FSAccess(objPtr, mode) == 0);
    }
    Tcl_SetBooleanObj(Tcl_GetObjResult(interp), value);

    return TCL_OK;
}

/*







|


|





|


|







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
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
  
static int
CheckAccess(interp, pathPtr, mode)
    Tcl_Interp *interp;		/* Interp for status return.  Must not be
				 * NULL. */
    Tcl_Obj *pathPtr;		/* Name of file to check. */
    int mode;			/* Attribute to check; passed as argument to
				 * access(). */
{
    int value;
    
    if (Tcl_FSConvertToPathType(interp, pathPtr) != TCL_OK) {
	value = 0;
    } else {
	value = (Tcl_FSAccess(pathPtr, mode) == 0);
    }
    Tcl_SetBooleanObj(Tcl_GetObjResult(interp), value);

    return TCL_OK;
}

/*
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
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */

static int
GetStatBuf(interp, objPtr, statProc, statPtr)
    Tcl_Interp *interp;		/* Interp for error return.  May be NULL. */
    Tcl_Obj *objPtr;		/* Path name to examine. */
    Tcl_FSStatProc *statProc;	/* Either stat() or lstat() depending on
				 * desired behavior. */
    Tcl_StatBuf *statPtr;	/* Filled with info about file obtained by
				 * calling (*statProc)(). */
{
    int status;
    
    if (Tcl_FSConvertToPathType(interp, objPtr) != TCL_OK) {
	return TCL_ERROR;
    }

    status = (*statProc)(objPtr, statPtr);
    
    if (status < 0) {
	if (interp != NULL) {
	    Tcl_AppendResult(interp, "could not read \"",
		    Tcl_GetString(objPtr), "\": ",
		    Tcl_PosixError(interp), (char *) NULL);
	}
	return TCL_ERROR;
    }
    return TCL_OK;
}








|

|







|



|




|







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
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */

static int
GetStatBuf(interp, pathPtr, statProc, statPtr)
    Tcl_Interp *interp;		/* Interp for error return.  May be NULL. */
    Tcl_Obj *pathPtr;		/* Path name to examine. */
    Tcl_FSStatProc *statProc;	/* Either stat() or lstat() depending on
				 * desired behavior. */
    Tcl_StatBuf *statPtr;	/* Filled with info about file obtained by
				 * calling (*statProc)(). */
{
    int status;
    
    if (Tcl_FSConvertToPathType(interp, pathPtr) != TCL_OK) {
	return TCL_ERROR;
    }

    status = (*statProc)(pathPtr, statPtr);
    
    if (status < 0) {
	if (interp != NULL) {
	    Tcl_AppendResult(interp, "could not read \"",
		    Tcl_GetString(pathPtr), "\": ",
		    Tcl_PosixError(interp), (char *) NULL);
	}
	return TCL_ERROR;
    }
    return TCL_OK;
}

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
 *
 *----------------------------------------------------------------------
 */

static int
StoreStatData(interp, varName, statPtr)
    Tcl_Interp *interp;			/* Interpreter for error reports. */
    char *varName;			/* Name of associative array variable
					 * in which to store stat results. */
    Tcl_StatBuf *statPtr;		/* Pointer to buffer containing
					 * stat data to store in varName. */
{
    Tcl_Obj *var = Tcl_NewStringObj(varName, -1);
    Tcl_Obj *field = Tcl_NewObj();
    Tcl_Obj *value;
    register unsigned short mode;

    /*
     * Assume Tcl_ObjSetVar2() does not keep a copy of the field name!



     */
#define STORE_ARY(fieldName, object) \
    Tcl_SetStringObj(field, (fieldName), -1); \
    value = (object); \
    if (Tcl_ObjSetVar2(interp,var,field,value,TCL_LEAVE_ERR_MSG) == NULL) { \
	Tcl_DecrRefCount(var); \
	Tcl_DecrRefCount(field); \
	Tcl_DecrRefCount(value); \
	return TCL_ERROR; \
    }

    Tcl_IncrRefCount(var);
    Tcl_IncrRefCount(field);
    STORE_ARY("dev",   Tcl_NewLongObj((long)statPtr->st_dev));
    /*
     * Watch out porters; the inode is meant to be an *unsigned* value,
     * so the cast might fail when there isn't a real arithmentic 'long
     * long' type...
     */







|




<






>
>
>




|
<





<







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
 *
 *----------------------------------------------------------------------
 */

static int
StoreStatData(interp, varName, statPtr)
    Tcl_Interp *interp;			/* Interpreter for error reports. */
    Tcl_Obj *varName;			/* Name of associative array variable
					 * in which to store stat results. */
    Tcl_StatBuf *statPtr;		/* Pointer to buffer containing
					 * stat data to store in varName. */
{

    Tcl_Obj *field = Tcl_NewObj();
    Tcl_Obj *value;
    register unsigned short mode;

    /*
     * Assume Tcl_ObjSetVar2() does not keep a copy of the field name!
     *
     * Might be a better idea to call Tcl_SetVar2Ex() instead so we
     * don't have to make assumptions that might go wrong later.
     */
#define STORE_ARY(fieldName, object) \
    Tcl_SetStringObj(field, (fieldName), -1); \
    value = (object); \
    if (Tcl_ObjSetVar2(interp,varName,field,value,TCL_LEAVE_ERR_MSG) == NULL) { \

	Tcl_DecrRefCount(field); \
	Tcl_DecrRefCount(value); \
	return TCL_ERROR; \
    }


    Tcl_IncrRefCount(field);
    STORE_ARY("dev",   Tcl_NewLongObj((long)statPtr->st_dev));
    /*
     * Watch out porters; the inode is meant to be an *unsigned* value,
     * so the cast might fail when there isn't a real arithmentic 'long
     * long' type...
     */
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
    STORE_ARY("atime", Tcl_NewLongObj((long)statPtr->st_atime));
    STORE_ARY("mtime", Tcl_NewLongObj((long)statPtr->st_mtime));
    STORE_ARY("ctime", Tcl_NewLongObj((long)statPtr->st_ctime));
    mode = (unsigned short) statPtr->st_mode;
    STORE_ARY("mode",  Tcl_NewIntObj(mode));
    STORE_ARY("type",  Tcl_NewStringObj(GetTypeFromMode(mode), -1));
#undef STORE_ARY
    Tcl_DecrRefCount(var);
    Tcl_DecrRefCount(field);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *







<







1599
1600
1601
1602
1603
1604
1605

1606
1607
1608
1609
1610
1611
1612
    STORE_ARY("atime", Tcl_NewLongObj((long)statPtr->st_atime));
    STORE_ARY("mtime", Tcl_NewLongObj((long)statPtr->st_mtime));
    STORE_ARY("ctime", Tcl_NewLongObj((long)statPtr->st_ctime));
    mode = (unsigned short) statPtr->st_mode;
    STORE_ARY("mode",  Tcl_NewIntObj(mode));
    STORE_ARY("type",  Tcl_NewStringObj(GetTypeFromMode(mode), -1));
#undef STORE_ARY

    Tcl_DecrRefCount(field);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
	     * this happens, which can lead to some wierd crashes,
	     * like Bug #494348...)
	     */

	    result = Tcl_ListObjGetElements(interp, argObjv[1+i*2],
		    &varcList[i], &varvList[i]);
	    if (result != TCL_OK) {
		panic("Tcl_ForeachObjCmd: could not reconvert variable list %d to a list object\n", i);
	    }
	    result = Tcl_ListObjGetElements(interp, argObjv[2+i*2],
		    &argcList[i], &argvList[i]);
	    if (result != TCL_OK) {
		panic("Tcl_ForeachObjCmd: could not reconvert value list %d to a list object\n", i);
	    }
	    
	    for (v = 0;  v < varcList[i];  v++) {
		int k = index[i]++;
		Tcl_Obj *valuePtr, *varValuePtr;
		int isEmptyObj = 0;
		







|




|







1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
	     * this happens, which can lead to some wierd crashes,
	     * like Bug #494348...)
	     */

	    result = Tcl_ListObjGetElements(interp, argObjv[1+i*2],
		    &varcList[i], &varvList[i]);
	    if (result != TCL_OK) {
		Tcl_Panic("Tcl_ForeachObjCmd: could not reconvert variable list %d to a list object\n", i);
	    }
	    result = Tcl_ListObjGetElements(interp, argObjv[2+i*2],
		    &argcList[i], &argvList[i]);
	    if (result != TCL_OK) {
		Tcl_Panic("Tcl_ForeachObjCmd: could not reconvert value list %d to a list object\n", i);
	    }
	    
	    for (v = 0;  v < varcList[i];  v++) {
		int k = index[i]++;
		Tcl_Obj *valuePtr, *varValuePtr;
		int isEmptyObj = 0;
		
Changes to generic/tclCmdIL.c.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclCmdIL.c,v 1.50.2.3 2003/10/16 02:28:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include "tclRegexp.h"

/*







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclCmdIL.c,v 1.50.2.4 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include "tclRegexp.h"

/*
2020
2021
2022
2023
2024
2025
2026









































































































2027
2028
2029
2030
2031
2032
2033
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *









































































































 * Tcl_LindexObjCmd --
 *
 *	This object-based procedure is invoked to process the "lindex" Tcl
 *	command. See the user documentation for details on what it does.
 *
 * Results:
 *	A standard Tcl object result.







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







2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
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
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_LassignObjCmd --
 *
 *	This object-based procedure is invoked to process the "lassign" Tcl
 *	command. See the user documentation for details on what it does.
 *
 * Results:
 *	A standard Tcl object result.
 *
 * Side effects:
 *	See the user documentation.
 *
 *----------------------------------------------------------------------
 */

    /* ARGSUSED */
int
Tcl_LassignObjCmd(dummy, interp, objc, objv)
    ClientData dummy;		/* Not used. */
    Tcl_Interp *interp;		/* Current interpreter. */
    int objc;			/* Number of arguments. */
    Tcl_Obj *CONST objv[];	/* Argument objects. */
{
    Tcl_Obj *valueObj;		/* Value to assign to variable, as read from
				 * the list object or created in the emptyObj
				 * variable. */
    Tcl_Obj *emptyObj = NULL;	/* If non-NULL, an empty object created for
				 * being assigned to variables once we have
				 * run out of values from the list object. */
    Tcl_Obj **listObjv;		/* The contents of the list. */
    int listObjc;		/* The length of the list. */
    int i;

    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 1, objv, "list varname ?varname ...?");
	return TCL_ERROR;
    }

    /*
     * First assign values out of the list to variables.
     */

    for (i=0 ; i+2<objc ; i++) {
	/*
	 * We do this each time round the loop because that is robust
	 * against shimmering nasties.
	 */
	if (Tcl_ListObjIndex(interp, objv[1], i, &valueObj) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (valueObj == NULL) {
	    if (emptyObj == NULL) {
		TclNewObj(emptyObj);
		Tcl_IncrRefCount(emptyObj);
	    }
	    valueObj = emptyObj;
	}
	/*
	 * Make sure the reference count for the value being assigned
	 * is greater than one (other reference minimally in the list)
	 * so we can't get hammered by shimmering.
	 */
	Tcl_IncrRefCount(valueObj);
	if (Tcl_ObjSetVar2(interp, objv[i+2], NULL, valueObj,
		TCL_LEAVE_ERR_MSG) == NULL) {
	    Tcl_DecrRefCount(valueObj);
	    if (emptyObj != NULL) {
		Tcl_DecrRefCount(emptyObj);
	    }
	    return TCL_ERROR;
	}
	Tcl_DecrRefCount(valueObj);
    }
    if (emptyObj != NULL) {
	Tcl_DecrRefCount(emptyObj);
    }

    /*
     * Now place a list of any values left over into the interpreter
     * result.
     *
     * First, figure out how many values were not assigned by getting
     * the length of the list.  Note that I do not expect this
     * operation to fail.
     */

    if (Tcl_ListObjGetElements(interp, objv[1],
	    &listObjc, &listObjv) != TCL_OK) {
	return TCL_ERROR;
    }

    if (listObjc > objc-2) {
	/*
	 * OK, there were left-overs.  Make a list of them and slap
	 * that back in the interpreter result.
	 */
	Tcl_SetObjResult(interp,
		Tcl_NewListObj(listObjc - objc + 2, listObjv + objc - 2));
    }

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_LindexObjCmd --
 *
 *	This object-based procedure is invoked to process the "lindex" Tcl
 *	command. See the user documentation for details on what it does.
 *
 * Results:
 *	A standard Tcl object result.
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
int
Tcl_LrepeatObjCmd(dummy, interp, objc, objv)
    ClientData dummy;			/* Not used. */
    Tcl_Interp *interp;			/* Current interpreter. */
    register int objc;			/* Number of arguments. */
    register Tcl_Obj *CONST objv[];	/* The argument objects. */
{
    int elementCount, i, j, k, result;
    Tcl_Obj **dataArray;

    /* 
     * Check arguments for legality:
     *		lrepeat posInt value ?value ...?
     */








|







2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
int
Tcl_LrepeatObjCmd(dummy, interp, objc, objv)
    ClientData dummy;			/* Not used. */
    Tcl_Interp *interp;			/* Current interpreter. */
    register int objc;			/* Number of arguments. */
    register Tcl_Obj *CONST objv[];	/* The argument objects. */
{
    int elementCount, i, result;
    Tcl_Obj **dataArray;

    /* 
     * Check arguments for legality:
     *		lrepeat posInt value ?value ...?
     */

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
    objv += 2;

    /*
     * Create workspace array large enough to hold each init value
     * elementCount times.  Note that we don't bother with stack
     * allocation for this, as we expect this function to be used
     * mainly when stack allocation would be inappropriate anyway.




     *
     * POSSIBLE FUTURE ENHANCEMENT: Build the resulting list object
     * directly and avoid a copy.




     */






    dataArray = (Tcl_Obj **) ckalloc(elementCount * objc * sizeof(Tcl_Obj));







    /*
     * Set the elements.  Note that this ends up setting k to the


     * total number of elements.
     */








    k = 0;

    for (i=0 ; i<elementCount ; i++) {
	for (j=0 ; j<objc ; j++) {
	    dataArray[k++] = objv[j];

	}
    }

    /*
     * Build the result list, clean up and return.
     */

    Tcl_SetObjResult(interp, Tcl_NewListObj(k, dataArray));
    ckfree((char*) dataArray);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_LreplaceObjCmd --







>
>
>
>

<
<
>
>
>
>


>
>
>
>
>
|
>

>
>
>
>
>

|
>
>
|


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







|
<







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
    objv += 2;

    /*
     * Create workspace array large enough to hold each init value
     * elementCount times.  Note that we don't bother with stack
     * allocation for this, as we expect this function to be used
     * mainly when stack allocation would be inappropriate anyway.
     * 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.
     *


     * We allocate using attemptckalloc() because if we ask for
     * something big but can't get it, we've still got a high chance
     * of having a proper failover strategy.  If *that* fails to get
     * memory, Tcl_Panic() will happen just a few lines lower...
     */

    if ((unsigned)elementCount > INT_MAX/sizeof(Tcl_Obj *)/objc) {
	Tcl_AppendResult(interp, "overflow of maximum list length", NULL);
	return TCL_ERROR;
    }

    dataArray = (Tcl_Obj **)
	    attemptckalloc(elementCount * objc * sizeof(Tcl_Obj *));

    if (dataArray == NULL) {
	Tcl_AppendResult(interp, "insufficient memory to create list", NULL);
	return TCL_ERROR;
    }

    /*
     * Set the elements.  Note that we handle the common degenerate
     * case of a single value being repeated separately to permit the
     * compiler as much room as possible to optimize a loop that might
     * be run a very large number of times.
     */

    if (objc == 1) {
	register Tcl_Obj *tmpPtr = objv[0];

	for (i=0 ; i<elementCount ; i++) {
	    dataArray[i] = tmpPtr;
	}
    } else {
	int j, k = 0;

	for (i=0 ; i<elementCount ; i++) {
	    for (j=0 ; j<objc ; j++) {
		dataArray[k++] = objv[j];
	    }
	}
    }

    /*
     * Build the result list, clean up and return.
     */

    Tcl_SetObjResult(interp, TclNewListObjDirect(elementCount*objc,dataArray));

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_LreplaceObjCmd --
Changes to generic/tclCmdMZ.c.
1
2
3
4
5
6
7
8
9
10
11
12

13
14
15
16
17
18
19
20
21
22
23
24
/* 
 * tclCmdMZ.c --
 *
 *	This file contains the top-level command routines for most of
 *	the Tcl built-in commands whose names begin with the letters
 *	M to Z.  It contains only commands in the generic core (i.e.
 *	those that don't depend much upon UNIX facilities).
 *
 * Copyright (c) 1987-1993 The Regents of the University of California.
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 Scriptics Corporation.
 * Copyright (c) 2002 ActiveState Corporation.

 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclCmdMZ.c,v 1.90.2.5 2003/10/16 02:28:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include "tclRegexp.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
/* 
 * tclCmdMZ.c --
 *
 *	This file contains the top-level command routines for most of
 *	the Tcl built-in commands whose names begin with the letters
 *	M to Z.  It contains only commands in the generic core (i.e.
 *	those that don't depend much upon UNIX facilities).
 *
 * Copyright (c) 1987-1993 The Regents of the University of California.
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 Scriptics Corporation.
 * Copyright (c) 2002 ActiveState Corporation.
 * Copyright (c) 2003 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: tclCmdMZ.c,v 1.90.2.6 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include "tclRegexp.h"

/*
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
int
Tcl_ReturnObjCmd(dummy, interp, objc, objv)
    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 code, level;




    Tcl_Obj *valuePtr;

    /* Start with the default options */
    if (iPtr->returnOpts != iPtr->defaultReturnOpts) {
	Tcl_DecrRefCount(iPtr->returnOpts);
	iPtr->returnOpts = iPtr->defaultReturnOpts;
	Tcl_IncrRefCount(iPtr->returnOpts);
    }

    objv++, objc--;
    if (objc) {
	/* We're going to add our options, so manage Tcl_Obj sharing */
	Tcl_DecrRefCount(iPtr->returnOpts);
	iPtr->returnOpts = Tcl_DuplicateObj(iPtr->returnOpts);
	Tcl_IncrRefCount(iPtr->returnOpts);
    }
    
    for (;  objc > 1;  objv += 2, objc -= 2) {
	int optLen;
	CONST char *opt = Tcl_GetStringFromObj(objv[0], &optLen);
	if ((optLen == 8) && (*opt == '-') && (strcmp(opt, "-options") == 0)) {
	    Tcl_DictSearch search;
	    int done = 0;
	    Tcl_Obj *keyPtr;
	    Tcl_Obj *dict = objv[1];

	    nestedOptions:
	    if (TCL_ERROR == Tcl_DictObjFirst(NULL, dict,
		    &search, &keyPtr, &valuePtr, &done)) {
		/* Value is not a legal dictionary */
		Tcl_DecrRefCount(iPtr->returnOpts);
		iPtr->returnOpts = iPtr->defaultReturnOpts;
		Tcl_IncrRefCount(iPtr->returnOpts);
		Tcl_ResetResult(interp);
		Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
			"bad -options value: expected dictionary but got \"",
			Tcl_GetString(objv[1]), "\"", (char *) NULL);
		return TCL_ERROR;
	    }

	    while (!done) {
		Tcl_DictObjPut(NULL, iPtr->returnOpts, keyPtr, valuePtr);
		Tcl_DictObjNext(&search, &keyPtr, &valuePtr, &done);
	    }

	    valuePtr = NULL;
	    Tcl_DictObjGet(NULL, iPtr->returnOpts,
		    iPtr->returnOptionsKey, &valuePtr);
	    if (valuePtr != NULL) {
		dict = valuePtr;
		Tcl_DictObjRemove(NULL, iPtr->returnOpts,
			iPtr->returnOptionsKey);
		goto nestedOptions;
	    }

	} else {
	    Tcl_DictObjPut(NULL, iPtr->returnOpts, objv[0], objv[1]);
	}
    }

    /* Check for bogus -code value */
    Tcl_DictObjGet(NULL, iPtr->returnOpts, iPtr->returnCodeKey, &valuePtr);
    if (TCL_ERROR == Tcl_GetIntFromObj(NULL, valuePtr, &code)) {
	static CONST char *returnCodes[] = {
	    "ok", "error", "return", "break", "continue", NULL
	};

	if (TCL_ERROR == Tcl_GetIndexFromObj(NULL, valuePtr, returnCodes,
		NULL, TCL_EXACT, &code)) {
	    /* Value is not a legal return code */
	    Tcl_DecrRefCount(iPtr->returnOpts);
	    iPtr->returnOpts = iPtr->defaultReturnOpts;
	    Tcl_IncrRefCount(iPtr->returnOpts);
	    Tcl_ResetResult(interp);
	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		    "bad completion code \"",
		    Tcl_GetString(valuePtr),
		    "\": must be ok, error, return, break, ",
		    "continue, or an integer", (char *) NULL);
	    return TCL_ERROR;
	}
	/* Have a legal string value for a return code; convert to integer */
	Tcl_DictObjPut(NULL, iPtr->returnOpts,
		iPtr->returnCodeKey, Tcl_NewIntObj(code));
    }

    /* Check for bogus -level value */
    Tcl_DictObjGet(NULL, iPtr->returnOpts, iPtr->returnLevelKey, &valuePtr);
    if (TCL_ERROR == Tcl_GetIntFromObj(NULL, valuePtr, &level) || (level < 0)) {
	/* Value is not a legal level */
	Tcl_DecrRefCount(iPtr->returnOpts);
	iPtr->returnOpts = iPtr->defaultReturnOpts;
	Tcl_IncrRefCount(iPtr->returnOpts);
	Tcl_ResetResult(interp);
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		"bad -level value: expected non-negative integer but got \"",
		Tcl_GetString(valuePtr), "\"", (char *) NULL);
	return TCL_ERROR;
    }

    /* 
     * Convert [return -code return -level X] to
     * [return -code ok -level X+1]
     */
    if (code == TCL_RETURN) {
	level++;
	Tcl_DictObjPut(NULL, iPtr->returnOpts,
		iPtr->returnLevelKey, Tcl_NewIntObj(level));
	Tcl_DictObjPut(NULL, iPtr->returnOpts,
		iPtr->returnCodeKey, Tcl_NewIntObj(TCL_OK));
    }

    if (level == 0) {
	if (code == TCL_ERROR) {
	    valuePtr = NULL;
	    Tcl_DictObjGet(NULL, iPtr->returnOpts,
		    iPtr->returnErrorinfoKey, &valuePtr);







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


|
|

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







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
int
Tcl_ReturnObjCmd(dummy, interp, objc, objv)
    ClientData dummy;		/* Not used. */
    Tcl_Interp *interp;		/* Current interpreter. */
    int objc;			/* Number of arguments. */
    Tcl_Obj *CONST objv[];	/* Argument objects. */
{
    int code, level;
    Tcl_Obj *returnOpts;

    /*
     * General syntax: [return ?-option value ...? ?result?]
     * An even number of words means an explicit result argument is present.
     */
    int explicitResult = (0 == (objc % 2));
    int numOptionWords = objc - 1 - explicitResult;

    if (TCL_ERROR == TclMergeReturnOptions(interp, numOptionWords, objv+1,
	    &returnOpts, &code, &level)) {
	return TCL_ERROR;
    }

    code = TclProcessReturn(interp, code, level, returnOpts);
    if (explicitResult) {
	Tcl_SetObjResult(interp, objv[objc-1]);
    }
    return code;
}

/*
 *----------------------------------------------------------------------
 *
 * TclProcessReturn --
 *
 *	Does the work of the [return] command based on the code,
 *	level, and returnOpts arguments.  Note that the code argument
 *	must agree with the -code entry in returnOpts and the level
 *	argument must agree with the -level entry in returnOpts, as
 *	is the case for values returned from TclMergeReturnOptions.
 *
 * Results:
 *	Returns the return code the [return] command should return.
 *
 * Side effects:
 *	When the return code is TCL_ERROR, the values of ::errorInfo
 *	and ::errorCode may be updated.
 *
 *----------------------------------------------------------------------
 */
int
TclProcessReturn(interp, code, level, returnOpts)
    Tcl_Interp *interp;
    int code;
    int level;
    Tcl_Obj *returnOpts;
{
    Interp *iPtr = (Interp *) interp;
    Tcl_Obj *valuePtr;

    /* Store the merged return options */
    if (iPtr->returnOpts != returnOpts) {
	Tcl_DecrRefCount(iPtr->returnOpts);














































	iPtr->returnOpts = returnOpts;




















	Tcl_IncrRefCount(iPtr->returnOpts);





































    }

    if (level == 0) {
	if (code == TCL_ERROR) {
	    valuePtr = NULL;
	    Tcl_DictObjGet(NULL, iPtr->returnOpts,
		    iPtr->returnErrorinfoKey, &valuePtr);
978
979
980
981
982
983
984

985
986






















































987




988



































989
990



















































991
992
993
994
995
996
997
			valuePtr, TCL_GLOBAL_ONLY);
		iPtr->flags |= ERROR_CODE_SET;
	    }
	}
    } else {
	code = TCL_RETURN;
    }


    if (objc == 1) {






















































	Tcl_SetObjResult(interp, objv[0]);




    }



































    return code;




















































}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_SourceObjCmd --
 *







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







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
			valuePtr, TCL_GLOBAL_ONLY);
		iPtr->flags |= ERROR_CODE_SET;
	    }
	}
    } else {
	code = TCL_RETURN;
    }
    return code;
}

/*
 *----------------------------------------------------------------------
 *
 * TclMergeReturnOptions --
 *
 *	Parses, checks, and stores the options to the [return] command.
 *
 * Results:
 *	Returns TCL_ERROR is any of the option values are invalid.
 *	Otherwise, returns TCL_OK, and writes the returnOpts, code,
 *	and level values to the pointers provided.
 *
 * Side effects:
 * 	None.
 *
 *----------------------------------------------------------------------
 */

int
TclMergeReturnOptions(interp, objc, objv, optionsPtrPtr, codePtr, levelPtr)
    Tcl_Interp *interp;		/* Current interpreter. */
    int objc;			/* Number of arguments. */
    Tcl_Obj *CONST objv[];	/* Argument objects. */
    Tcl_Obj **optionsPtrPtr;	/* If not NULL, points to space for a
				 * (Tcl_Obj *) where the pointer to the
				 * merged return options dictionary should
				 * be written */
    int *codePtr;		/* If not NULL, points to space where the
				 * -code value should be written */
    int *levelPtr;		/* If not NULL, points to space where the
				 * -level value should be written */
{
    Interp *iPtr = (Interp *) interp;
    int code, level, size;
    Tcl_Obj *valuePtr;
    Tcl_Obj *returnOpts = Tcl_DuplicateObj(iPtr->defaultReturnOpts);

    for (;  objc > 1;  objv += 2, objc -= 2) {
	int optLen;
	CONST char *opt = Tcl_GetStringFromObj(objv[0], &optLen);
	int compareLen;
	CONST char *compare =
		Tcl_GetStringFromObj(iPtr->returnOptionsKey, &compareLen);

	if ((optLen == compareLen) && (strcmp(opt, compare) == 0)) {
	    Tcl_DictSearch search;
	    int done = 0;
	    Tcl_Obj *keyPtr;
	    Tcl_Obj *dict = objv[1];

	    nestedOptions:
	    if (TCL_ERROR == Tcl_DictObjFirst(NULL, dict,
		    &search, &keyPtr, &valuePtr, &done)) {
		/* Value is not a legal dictionary */
		Tcl_ResetResult(interp);
		Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "bad ",
			compare, " value: expected dictionary but got \"",
			Tcl_GetString(objv[1]), "\"", (char *) NULL);
		return TCL_ERROR;
	    }

	    while (!done) {
		Tcl_DictObjPut(NULL, returnOpts, keyPtr, valuePtr);
		Tcl_DictObjNext(&search, &keyPtr, &valuePtr, &done);
	    }

	    valuePtr = NULL;
	    Tcl_DictObjGet(NULL, returnOpts, iPtr->returnOptionsKey, &valuePtr);
	    if (valuePtr != NULL) {
		dict = valuePtr;
		Tcl_DictObjRemove(NULL, returnOpts, iPtr->returnOptionsKey);
		goto nestedOptions;
	    }

	} else {
	    Tcl_DictObjPut(NULL, returnOpts, objv[0], objv[1]);
	}
    }

    /* Check for bogus -code value */
    Tcl_DictObjGet(NULL, returnOpts, iPtr->returnCodeKey, &valuePtr);
    if (TCL_ERROR == Tcl_GetIntFromObj(NULL, valuePtr, &code)) {
	static CONST char *returnCodes[] = {
	    "ok", "error", "return", "break", "continue", NULL
	};

	if (TCL_ERROR == Tcl_GetIndexFromObj(NULL, valuePtr, returnCodes,
		NULL, TCL_EXACT, &code)) {
	    /* Value is not a legal return code */
	    Tcl_ResetResult(interp);
	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		    "bad completion code \"",
		    Tcl_GetString(valuePtr),
		    "\": must be ok, error, return, break, ",
		    "continue, or an integer", (char *) NULL);
	    return TCL_ERROR;
	}
	/* Have a legal string value for a return code; convert to integer */
	Tcl_DictObjPut(NULL, returnOpts,
		iPtr->returnCodeKey, Tcl_NewIntObj(code));
    }

    /* Check for bogus -level value */
    Tcl_DictObjGet(NULL, returnOpts, iPtr->returnLevelKey, &valuePtr);
    if (TCL_ERROR == Tcl_GetIntFromObj(NULL, valuePtr, &level) || (level < 0)) {
	/* Value is not a legal level */
	Tcl_ResetResult(interp);
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		"bad -level value: expected non-negative integer but got \"",
		Tcl_GetString(valuePtr), "\"", (char *) NULL);
	return TCL_ERROR;
    }

    /* 
     * Convert [return -code return -level X] to
     * [return -code ok -level X+1]
     */
    if (code == TCL_RETURN) {
	level++;
	Tcl_DictObjPut(NULL, returnOpts,
		iPtr->returnLevelKey, Tcl_NewIntObj(level));
	Tcl_DictObjPut(NULL, returnOpts,
		iPtr->returnCodeKey, Tcl_NewIntObj(TCL_OK));
    }

    /*
     * Check if we just have the default options.  If so, use them.
     * A dictionary equality test would be more robust, but seems
     * tricky, to say the least.
     */
    Tcl_DictObjSize(NULL, returnOpts, &size);
    if (size == 2 && code == TCL_OK && level == 1) {
	Tcl_DecrRefCount(returnOpts);
	returnOpts = iPtr->defaultReturnOpts;
    }
    if (codePtr != NULL) {
	*codePtr = code;
    }
    if (levelPtr != NULL) {
	*levelPtr = level;
    }
    if ((optionsPtrPtr == NULL) && (returnOpts != iPtr->defaultReturnOpts)) {
	/* not passing back the options (?!), so clean them up */
	Tcl_DecrRefCount(returnOpts);
    } else {
	*optionsPtrPtr = returnOpts;
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_SourceObjCmd --
 *
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
		break;
	    }
	    case SUBST_NOVARS: {
		flags &= ~TCL_SUBST_VARIABLES;
		break;
	    }
	    default: {
		panic("Tcl_SubstObjCmd: bad option index to SubstOptions");
	    }
	}
    }
    if (i != (objc-1)) {
	Tcl_WrongNumArgs(interp, 1, objv,
		"?-nobackslashes? ?-nocommands? ?-novariables? string");
	return TCL_ERROR;







|







2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
		break;
	    }
	    case SUBST_NOVARS: {
		flags &= ~TCL_SUBST_VARIABLES;
		break;
	    }
	    default: {
		Tcl_Panic("Tcl_SubstObjCmd: bad option index to SubstOptions");
	    }
	}
    }
    if (i != (objc-1)) {
	Tcl_WrongNumArgs(interp, 1, objv,
		"?-nobackslashes? ?-nocommands? ?-novariables? string");
	return TCL_ERROR;
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
int
Tcl_SwitchObjCmd(dummy, interp, objc, objv)
    ClientData dummy;		/* Not used. */
    Tcl_Interp *interp;		/* Current interpreter. */
    int objc;			/* Number of arguments. */
    Tcl_Obj *CONST objv[];	/* Argument objects. */
{
    int i, j, index, mode, matched, result, splitObjs;
    char *string, *pattern;
    Tcl_Obj *stringObj;
    Tcl_Obj *CONST *savedObjv = objv;

    static CONST char *options[] = {
	"-exact",	"-glob",	"-regexp",	"--", 
	NULL
    };
    enum options {
	OPT_EXACT,	OPT_GLOB,	OPT_REGEXP,	OPT_LAST
    };

    mode = OPT_EXACT;



    for (i = 1; i < objc; i++) {
	string = Tcl_GetString(objv[i]);
	if (string[0] != '-') {
	    break;
	}
	if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0, 
		&index) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (index == OPT_LAST) {
	    i++;
	    break;
	}



























	mode = index;

    }

    if (objc - i < 2) {
	Tcl_WrongNumArgs(interp, 1, objv,
		"?switches? string pattern body ... ?default body?");
	return TCL_ERROR;










    }

    stringObj = objv[i];
    objc -= i + 1;
    objv += i + 1;

    /*







|

|

>

|



|



>
>
>













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






>
>
>
>
>
>
>
>
>
>







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
int
Tcl_SwitchObjCmd(dummy, interp, objc, objv)
    ClientData dummy;		/* Not used. */
    Tcl_Interp *interp;		/* Current interpreter. */
    int objc;			/* Number of arguments. */
    Tcl_Obj *CONST objv[];	/* Argument objects. */
{
    int i, j, index, mode, matched, result, splitObjs, numMatchesSaved;
    char *string, *pattern;
    Tcl_Obj *stringObj, *indexVarObj, *matchVarObj;
    Tcl_Obj *CONST *savedObjv = objv;
    Tcl_RegExp regExpr = NULL;
    static CONST char *options[] = {
	"-exact", "-glob", "-indexvar", "-matchvar", "-regexp", "--", 
	NULL
    };
    enum options {
	OPT_EXACT, OPT_GLOB, OPT_INDEXV, OPT_MATCHV, OPT_REGEXP, OPT_LAST
    };

    mode = OPT_EXACT;
    indexVarObj = NULL;
    matchVarObj = NULL;
    numMatchesSaved = 0;
    for (i = 1; i < objc; i++) {
	string = Tcl_GetString(objv[i]);
	if (string[0] != '-') {
	    break;
	}
	if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0, 
		&index) != TCL_OK) {
	    return TCL_ERROR;
	}
	if (index == OPT_LAST) {
	    i++;
	    break;
	}

	/*
	 * Check for TIP#75 options specifying the variables to write
	 * regexp information into.
	 */

	if (index == OPT_INDEXV) {
	    i++;
	    if (i == objc) {
		Tcl_AppendResult(interp,
			"missing variable name argument to -indexvar option",
			(char *) NULL);
		return TCL_ERROR;
	    }
	    indexVarObj = objv[i];
	    numMatchesSaved = -1;
	} else if (index == OPT_MATCHV) {
	    i++;
	    if (i == objc) {
		Tcl_AppendResult(interp,
			"missing variable name argument to -matchvar option",
			(char *) NULL);
		return TCL_ERROR;
	    }
	    matchVarObj = objv[i];
	    numMatchesSaved = -1;
	} else {
	    mode = index;
	}
    }

    if (objc - i < 2) {
	Tcl_WrongNumArgs(interp, 1, objv,
		"?switches? string pattern body ... ?default body?");
	return TCL_ERROR;
    }
    if (indexVarObj != NULL && mode != OPT_REGEXP) {
	Tcl_AppendResult(interp,
		"-indexvar option requires -regexp option", (char *) NULL);
	return TCL_ERROR;
    }
    if (matchVarObj != NULL && mode != OPT_REGEXP) {
	Tcl_AppendResult(interp,
		"-matchvar option requires -regexp option", (char *) NULL);
	return TCL_ERROR;
    }

    stringObj = objv[i];
    objc -= i + 1;
    objv += i + 1;

    /*
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

	pattern = Tcl_GetString(objv[i]);

	matched = 0;
	if ((i == objc - 2) 
		&& (*pattern == 'd') 
		&& (strcmp(pattern, "default") == 0)) {


	    matched = 1;




























	} else {
	    switch (mode) {
		case OPT_EXACT:
		    matched = (strcmp(Tcl_GetString(stringObj), pattern) == 0);
		    break;
		case OPT_GLOB:
		    matched = Tcl_StringMatch(Tcl_GetString(stringObj),
			    pattern);
		    break;
		case OPT_REGEXP:





		    matched = Tcl_RegExpMatchObj(interp, stringObj, objv[i]);

		    if (matched < 0) {
			return TCL_ERROR;
		    }
		    break;
	    }
	}
	if (matched == 0) {
	    continue;
	}












































































	/*
	 * We've got a match. Find a body to execute, skipping bodies
	 * that are "-".
	 */

	for (j = i + 1; ; j += 2) {
	    if (j >= objc) {
		/*
		 * This shouldn't happen since we've checked that the
		 * last body is not a continuation...
		 */
		panic("fall-out when searching for body to match pattern");
	    }
	    if (strcmp(Tcl_GetString(objv[j]), "-") != 0) {
		break;
	    }
	}
	result = Tcl_EvalObjEx(interp, objv[j], 0);
	if (result == TCL_ERROR) {







>
>

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


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





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












|







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

	pattern = Tcl_GetString(objv[i]);

	matched = 0;
	if ((i == objc - 2) 
		&& (*pattern == 'd') 
		&& (strcmp(pattern, "default") == 0)) {
	    Tcl_Obj *emptyObj = NULL;

	    matched = 1;
	    /*
	     * If either indexVarObj or matchVarObj are non-NULL,
	     * we're in REGEXP mode but have reached the default
	     * clause anyway.  TIP#75 specifies that we set the
	     * variables to empty lists (== empty objects) in that
	     * case.
	     */
	    if (indexVarObj != NULL) {
		TclNewObj(emptyObj);
		if (Tcl_ObjSetVar2(interp, indexVarObj, NULL, emptyObj,
			TCL_LEAVE_ERR_MSG) == NULL) {
		    Tcl_DecrRefCount(emptyObj);
		    return TCL_ERROR;
		}
	    }
	    if (matchVarObj != NULL) {
		if (emptyObj == NULL) {
		    TclNewObj(emptyObj);
		}
		if (Tcl_ObjSetVar2(interp, matchVarObj, NULL, emptyObj,
			TCL_LEAVE_ERR_MSG) == NULL) {
		    if (indexVarObj == NULL) {
			Tcl_DecrRefCount(emptyObj);
		    }
		    return TCL_ERROR;
		}
	    }
	    numMatchesSaved = 0;
	} else {
	    switch (mode) {
	    case OPT_EXACT:
		matched = (strcmp(Tcl_GetString(stringObj), pattern) == 0);
		break;
	    case OPT_GLOB:
		matched = Tcl_StringMatch(Tcl_GetString(stringObj), pattern);

		break;
	    case OPT_REGEXP:
		regExpr = Tcl_GetRegExpFromObj(interp, objv[i],
			TCL_REG_ADVANCED);
		if (regExpr == NULL) {
		    return TCL_ERROR;
		}
		matched = Tcl_RegExpExecObj(interp, regExpr, stringObj, 0,
			numMatchesSaved, 0);
		if (matched < 0) {
		    return TCL_ERROR;
		}
		break;
	    }
	}
	if (matched == 0) {
	    continue;
	}

	/*
	 * We are operating in REGEXP mode and we need to store
	 * information about what we matched in some user-nominated
	 * arrays.  So build the lists of values and indices to write
	 * here.  [TIP#75]
	 */

	if (numMatchesSaved) {
	    Tcl_RegExpInfo info;
	    Tcl_Obj *matchesObj, *indicesObj = NULL;

	    Tcl_RegExpGetInfo(regExpr, &info);
	    if (matchVarObj != NULL) {
		TclNewObj(matchesObj);
	    } else {
		matchesObj = NULL;
	    }
	    if (indexVarObj != NULL) {
		TclNewObj(indicesObj);
	    }
	    for (j=0 ; j<=info.nsubs ; j++) {
		if (indexVarObj != NULL) {
		    Tcl_Obj *rangeObjAry[2];

		    rangeObjAry[0] = Tcl_NewLongObj(info.matches[j].start);
		    rangeObjAry[1] = Tcl_NewLongObj(info.matches[j].end);
		    /*
		     * Never fails; the object is always clean at this point.
		     */
		    Tcl_ListObjAppendElement(NULL, indicesObj,
			    Tcl_NewListObj(2, rangeObjAry));
		}
		if (matchVarObj != NULL) {
		    Tcl_Obj *substringObj;

		    substringObj = Tcl_GetRange(stringObj,
			    info.matches[j].start, info.matches[j].end-1);
		    /*
		     * Never fails; the object is always clean at this point.
		     */
		    Tcl_ListObjAppendElement(NULL, matchesObj, substringObj);
		}
	    }
	    if (indexVarObj != NULL) {
		if (Tcl_ObjSetVar2(interp, indexVarObj, NULL, indicesObj,
			TCL_LEAVE_ERR_MSG) == NULL) {
		    Tcl_DecrRefCount(indicesObj);
		    /*
		     * Careful!  Check to see if we have allocated the
		     * list of matched strings; if so (but there was
		     * an error assigning the indices list) we have a
		     * potential memory leak because the match list
		     * has not been written to a variable.  Except
		     * that we'll clean that up right now.
		     */
		    if (matchesObj != NULL) {
			Tcl_DecrRefCount(matchesObj);
		    }
		    return TCL_ERROR;
		}
	    }
	    if (matchVarObj != NULL) {
		if (Tcl_ObjSetVar2(interp, matchVarObj, NULL, matchesObj,
			TCL_LEAVE_ERR_MSG) == NULL) {
		    Tcl_DecrRefCount(matchesObj);
		    /*
		     * Unlike above, if indicesObj is non-NULL at this
		     * point, it will have been written to a variable
		     * already and will hence not be leaked.
		     */
		    return TCL_ERROR;
		}
	    }
	}

	/*
	 * We've got a match. Find a body to execute, skipping bodies
	 * that are "-".
	 */

	for (j = i + 1; ; j += 2) {
	    if (j >= objc) {
		/*
		 * This shouldn't happen since we've checked that the
		 * last body is not a continuation...
		 */
		Tcl_Panic("fall-out when searching for body to match pattern");
	    }
	    if (strcmp(Tcl_GetString(objv[j]), "-") != 0) {
		break;
	    }
	}
	result = Tcl_EvalObjEx(interp, objv[j], 0);
	if (result == TCL_ERROR) {
Changes to generic/tclCompCmds.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclCompCmds.c --
 *
 *	This file contains compilation procedures that compile various
 *	Tcl commands into a sequence of instructions ("bytecodes"). 
 *
 * Copyright (c) 1997-1998 Sun Microsystems, Inc.
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 * Copyright (c) 2002 ActiveState Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclCompCmds.c,v 1.49.2.1 2003/08/07 21:35:59 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"

/*
 * Prototypes for procedures defined later in this file:













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclCompCmds.c --
 *
 *	This file contains compilation procedures that compile various
 *	Tcl commands into a sequence of instructions ("bytecodes"). 
 *
 * Copyright (c) 1997-1998 Sun Microsystems, Inc.
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 * Copyright (c) 2002 ActiveState Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclCompCmds.c,v 1.49.2.2 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"

/*
 * Prototypes for procedures defined later in this file:
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
	Tcl_ResetResult(interp);
	Tcl_AppendToObj(Tcl_GetObjResult(interp),
		"wrong # args: should be \"append varName ?value value ...?\"",
		-1);
	return TCL_ERROR;
    } else if (numWords == 2) {
	/*
	 * append varName === set varName
	 */
        return TclCompileSetCmd(interp, parsePtr, envPtr);
    } else if (numWords > 3) {
	/*
	 * APPEND instructions currently only handle one value
	 */
        return TCL_OUT_LINE_COMPILE;







|







83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
	Tcl_ResetResult(interp);
	Tcl_AppendToObj(Tcl_GetObjResult(interp),
		"wrong # args: should be \"append varName ?value value ...?\"",
		-1);
	return TCL_ERROR;
    } else if (numWords == 2) {
	/*
	 * append varName == set varName
	 */
        return TclCompileSetCmd(interp, parsePtr, envPtr);
    } else if (numWords > 3) {
	/*
	 * APPEND instructions currently only handle one value
	 */
        return TCL_OUT_LINE_COMPILE;
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
	}
    }

    /*
     * We will compile the catch command. Emit a beginCatch instruction at
     * the start of the catch body: the subcommand it controls.
     */
    
    envPtr->exceptDepth++;
    envPtr->maxExceptDepth =
	TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth);
    range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
    TclEmitInstInt4(INST_BEGIN_CATCH4, range, envPtr);

    /*







|







288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
	}
    }

    /*
     * We will compile the catch command. Emit a beginCatch instruction at
     * the start of the catch body: the subcommand it controls.
     */

    envPtr->exceptDepth++;
    envPtr->maxExceptDepth =
	TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth);
    range = TclCreateExceptRange(CATCH_EXCEPTION_RANGE, envPtr);
    TclEmitInstInt4(INST_BEGIN_CATCH4, range, envPtr);

    /*
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336

    if (code != TCL_OK) {
	code = TCL_OUT_LINE_COMPILE;
	goto done;
    }
    envPtr->exceptArrayPtr[range].numCodeBytes =
	    (envPtr->codeNext - envPtr->codeStart) - startOffset;
		    
    /*
     * The "no errors" epilogue code: store the body's result into the
     * variable (if any), push "0" (TCL_OK) as the catch's "no error"
     * result, and jump around the "error case" code.
     */

    if (localIndex != -1) {







|







322
323
324
325
326
327
328
329
330
331
332
333
334
335
336

    if (code != TCL_OK) {
	code = TCL_OUT_LINE_COMPILE;
	goto done;
    }
    envPtr->exceptArrayPtr[range].numCodeBytes =
	    (envPtr->codeNext - envPtr->codeStart) - startOffset;

    /*
     * The "no errors" epilogue code: store the body's result into the
     * variable (if any), push "0" (TCL_OK) as the catch's "no error"
     * result, and jump around the "error case" code.
     */

    if (localIndex != -1) {
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381

    /*
     * Update the target of the jump after the "no errors" code, then emit
     * an endCatch instruction at the end of the catch command.
     */

    if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) {
	panic("TclCompileCatchCmd: bad jump distance %d\n",
		(envPtr->codeNext - envPtr->codeStart) - jumpFixup.codeOffset);
    }
    TclEmitOpcode(INST_END_CATCH, envPtr);

    done:
    envPtr->currStackDepth = savedStackDepth + 1;
    envPtr->exceptDepth--;







|







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

    /*
     * Update the target of the jump after the "no errors" code, then emit
     * an endCatch instruction at the end of the catch command.
     */

    if (TclFixupForwardJumpToHere(envPtr, &jumpFixup, 127)) {
	Tcl_Panic("TclCompileCatchCmd: bad jump distance %d\n",
		(envPtr->codeNext - envPtr->codeStart) - jumpFixup.codeOffset);
    }
    TclEmitOpcode(INST_END_CATCH, envPtr);

    done:
    envPtr->currStackDepth = savedStackDepth + 1;
    envPtr->exceptDepth--;
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
	if (code == TCL_ERROR) {
            Tcl_AddObjErrorInfo(interp,
	            "\n    (\"for\" initial command)", -1);
        }
	goto done;
    }
    TclEmitOpcode(INST_POP, envPtr);
   
    /*
     * Jump to the evaluation of the condition. This code uses the "loop
     * rotation" optimisation (which eliminates one branch from the loop).
     * "for start cond next body" produces then:
     *       start
     *       goto A
     *    B: body                : bodyCodeOffset







|







554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
	if (code == TCL_ERROR) {
            Tcl_AddObjErrorInfo(interp,
	            "\n    (\"for\" initial command)", -1);
        }
	goto done;
    }
    TclEmitOpcode(INST_POP, envPtr);

    /*
     * Jump to the evaluation of the condition. This code uses the "loop
     * rotation" optimisation (which eliminates one branch from the loop).
     * "for start cond next body" produces then:
     *       start
     *       goto A
     *    B: body                : bodyCodeOffset
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

    jumpDist = testCodeOffset - jumpEvalCondFixup.codeOffset;
    if (TclFixupForwardJump(envPtr, &jumpEvalCondFixup, jumpDist, 127)) {
	bodyCodeOffset += 3;
	nextCodeOffset += 3;
	testCodeOffset += 3;
    }
    
    envPtr->currStackDepth = savedStackDepth;
    code = TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
    if (code != TCL_OK) {
	if (code == TCL_ERROR) {
	    Tcl_AddObjErrorInfo(interp,
				"\n    (\"for\" test expression)", -1);
	}
	goto done;
    }
    envPtr->currStackDepth = savedStackDepth + 1;
    
    jumpDist = (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset;
    if (jumpDist > 127) {
	TclEmitInstInt4(INST_JUMP_TRUE4, -jumpDist, envPtr);
    } else {
	TclEmitInstInt1(INST_JUMP_TRUE1, -jumpDist, envPtr);
    }
    
    /*
     * Set the loop's offsets and break target.
     */

    envPtr->exceptArrayPtr[bodyRange].codeOffset = bodyCodeOffset;
    envPtr->exceptArrayPtr[bodyRange].continueOffset = nextCodeOffset;

    envPtr->exceptArrayPtr[nextRange].codeOffset = nextCodeOffset;

    envPtr->exceptArrayPtr[bodyRange].breakOffset =
            envPtr->exceptArrayPtr[nextRange].breakOffset =
	    (envPtr->codeNext - envPtr->codeStart);
    
    /*
     * The for command's result is an empty string.
     */

    envPtr->currStackDepth = savedStackDepth;
    TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
    code = TCL_OK;







|










|






|












|







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

    jumpDist = testCodeOffset - jumpEvalCondFixup.codeOffset;
    if (TclFixupForwardJump(envPtr, &jumpEvalCondFixup, jumpDist, 127)) {
	bodyCodeOffset += 3;
	nextCodeOffset += 3;
	testCodeOffset += 3;
    }

    envPtr->currStackDepth = savedStackDepth;
    code = TclCompileExprWords(interp, testTokenPtr, 1, envPtr);
    if (code != TCL_OK) {
	if (code == TCL_ERROR) {
	    Tcl_AddObjErrorInfo(interp,
				"\n    (\"for\" test expression)", -1);
	}
	goto done;
    }
    envPtr->currStackDepth = savedStackDepth + 1;

    jumpDist = (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset;
    if (jumpDist > 127) {
	TclEmitInstInt4(INST_JUMP_TRUE4, -jumpDist, envPtr);
    } else {
	TclEmitInstInt1(INST_JUMP_TRUE1, -jumpDist, envPtr);
    }

    /*
     * Set the loop's offsets and break target.
     */

    envPtr->exceptArrayPtr[bodyRange].codeOffset = bodyCodeOffset;
    envPtr->exceptArrayPtr[bodyRange].continueOffset = nextCodeOffset;

    envPtr->exceptArrayPtr[nextRange].codeOffset = nextCodeOffset;

    envPtr->exceptArrayPtr[bodyRange].breakOffset =
            envPtr->exceptArrayPtr[nextRange].breakOffset =
	    (envPtr->codeNext - envPtr->codeStart);

    /*
     * The for command's result is an empty string.
     */

    envPtr->currStackDepth = savedStackDepth;
    TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
    code = TCL_OK;
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
        varcList = (int *) ckalloc(numLists * sizeof(int));
        varvList = (CONST char ***) ckalloc(numLists * sizeof(CONST char **));
    }
    for (loopIndex = 0;  loopIndex < numLists;  loopIndex++) {
        varcList[loopIndex] = 0;
        varvList[loopIndex] = NULL;
    }
    
    /*
     * Set the exception stack depth.
     */ 

    envPtr->exceptDepth++;
    envPtr->maxExceptDepth =
	TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth);

    /*
     * Break up each var list and set the varcList and varvList arrays.
     * Don't compile the foreach inline if any var name needs substitutions
     * or isn't a scalar, or if any var list needs substitutions.
     */








|






|







773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
        varcList = (int *) ckalloc(numLists * sizeof(int));
        varvList = (CONST char ***) ckalloc(numLists * sizeof(CONST char **));
    }
    for (loopIndex = 0;  loopIndex < numLists;  loopIndex++) {
        varcList[loopIndex] = 0;
        varvList[loopIndex] = NULL;
    }

    /*
     * Set the exception stack depth.
     */ 

    envPtr->exceptDepth++;
    envPtr->maxExceptDepth =
	    TclMax(envPtr->exceptDepth, envPtr->maxExceptDepth);

    /*
     * Break up each var list and set the varcList and varvList arrays.
     * Don't compile the foreach inline if any var name needs substitutions
     * or isn't a scalar, or if any var list needs substitutions.
     */

843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
		/*create*/ 1, /*flags*/ VAR_SCALAR, procPtr);
	if (loopIndex == 0) {
	    firstValueTemp = tempVar;
	}
    }
    loopCtTemp = TclFindCompiledLocal(NULL, /*nameChars*/ 0,
	    /*create*/ 1, /*flags*/ VAR_SCALAR, procPtr);
    
    /*
     * Create and initialize the ForeachInfo and ForeachVarList data
     * structures describing this command. Then create a AuxData record
     * pointing to the ForeachInfo structure.
     */

    infoPtr = (ForeachInfo *) ckalloc((unsigned)







|







843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
		/*create*/ 1, /*flags*/ VAR_SCALAR, procPtr);
	if (loopIndex == 0) {
	    firstValueTemp = tempVar;
	}
    }
    loopCtTemp = TclFindCompiledLocal(NULL, /*nameChars*/ 0,
	    /*create*/ 1, /*flags*/ VAR_SCALAR, procPtr);

    /*
     * Create and initialize the ForeachInfo and ForeachVarList data
     * structures describing this command. Then create a AuxData record
     * pointing to the ForeachInfo structure.
     */

    infoPtr = (ForeachInfo *) ckalloc((unsigned)
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
    infoIndex = TclCreateAuxData((ClientData) infoPtr, &tclForeachInfoType, envPtr);

    /*
     * Evaluate then store each value list in the associated temporary.
     */

    range = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);
    
    loopIndex = 0;
    for (i = 0, tokenPtr = parsePtr->tokenPtr;
	    i < numWords-1;
	    i++, tokenPtr += (tokenPtr->numComponents + 1)) {
	if ((i%2 == 0) && (i > 0)) {
	    code = TclCompileTokens(interp, tokenPtr+1,
		    tokenPtr->numComponents, envPtr);







|







876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
    infoIndex = TclCreateAuxData((ClientData) infoPtr, &tclForeachInfoType, envPtr);

    /*
     * Evaluate then store each value list in the associated temporary.
     */

    range = TclCreateExceptRange(LOOP_EXCEPTION_RANGE, envPtr);

    loopIndex = 0;
    for (i = 0, tokenPtr = parsePtr->tokenPtr;
	    i < numWords-1;
	    i++, tokenPtr += (tokenPtr->numComponents + 1)) {
	if ((i%2 == 0) && (i > 0)) {
	    code = TclCompileTokens(interp, tokenPtr+1,
		    tokenPtr->numComponents, envPtr);
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
    }

    /*
     * Initialize the temporary var that holds the count of loop iterations.
     */

    TclEmitInstInt4(INST_FOREACH_START4, infoIndex, envPtr);
    
    /*
     * Top of loop code: assign each loop variable and check whether
     * to terminate the loop.
     */

    envPtr->exceptArrayPtr[range].continueOffset =
	    (envPtr->codeNext - envPtr->codeStart);
    TclEmitInstInt4(INST_FOREACH_STEP4, infoIndex, envPtr);
    TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFalseFixup);
    
    /*
     * Inline compile the loop body.
     */

    envPtr->exceptArrayPtr[range].codeOffset =
	    (envPtr->codeNext - envPtr->codeStart);
    code = TclCompileCmdWord(interp, bodyTokenPtr+1,







|









|







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
    }

    /*
     * Initialize the temporary var that holds the count of loop iterations.
     */

    TclEmitInstInt4(INST_FOREACH_START4, infoIndex, envPtr);

    /*
     * Top of loop code: assign each loop variable and check whether
     * to terminate the loop.
     */

    envPtr->exceptArrayPtr[range].continueOffset =
	    (envPtr->codeNext - envPtr->codeStart);
    TclEmitInstInt4(INST_FOREACH_STEP4, infoIndex, envPtr);
    TclEmitForwardJump(envPtr, TCL_FALSE_JUMP, &jumpFalseFixup);

    /*
     * Inline compile the loop body.
     */

    envPtr->exceptArrayPtr[range].codeOffset =
	    (envPtr->codeNext - envPtr->codeStart);
    code = TclCompileCmdWord(interp, bodyTokenPtr+1,
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
        }
	goto done;
    }
    envPtr->exceptArrayPtr[range].numCodeBytes =
	    (envPtr->codeNext - envPtr->codeStart)
	    - envPtr->exceptArrayPtr[range].codeOffset;
    TclEmitOpcode(INST_POP, envPtr);
	
    /*
     * Jump back to the test at the top of the loop. Generate a 4 byte jump
     * if the distance to the test is > 120 bytes. This is conservative and
     * ensures that we won't have to replace this jump if we later need to
     * replace the ifFalse jump with a 4 byte jump.
     */








|







936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
        }
	goto done;
    }
    envPtr->exceptArrayPtr[range].numCodeBytes =
	    (envPtr->codeNext - envPtr->codeStart)
	    - envPtr->exceptArrayPtr[range].codeOffset;
    TclEmitOpcode(INST_POP, envPtr);

    /*
     * Jump back to the test at the top of the loop. Generate a 4 byte jump
     * if the distance to the test is > 120 bytes. This is conservative and
     * ensures that we won't have to replace this jump if we later need to
     * replace the ifFalse jump with a 4 byte jump.
     */

985
986
987
988
989
990
991
992
993
994
995
996
997
998
999

    /*
     * Set the loop's break target.
     */

    envPtr->exceptArrayPtr[range].breakOffset =
	    (envPtr->codeNext - envPtr->codeStart);
    
    /*
     * The foreach command's result is an empty string.
     */

    envPtr->currStackDepth = savedStackDepth;
    TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
    envPtr->currStackDepth = savedStackDepth + 1;







|







985
986
987
988
989
990
991
992
993
994
995
996
997
998
999

    /*
     * Set the loop's break target.
     */

    envPtr->exceptArrayPtr[range].breakOffset =
	    (envPtr->codeNext - envPtr->codeStart);

    /*
     * The foreach command's result is an empty string.
     */

    envPtr->currStackDepth = savedStackDepth;
    TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
    envPtr->currStackDepth = savedStackDepth + 1;
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
				 * auxiliary data to duplicate. */
{
    register ForeachInfo *srcPtr = (ForeachInfo *) clientData;
    ForeachInfo *dupPtr;
    register ForeachVarList *srcListPtr, *dupListPtr;
    int numLists = srcPtr->numLists;
    int numVars, i, j;
    
    dupPtr = (ForeachInfo *) ckalloc((unsigned)
	    (sizeof(ForeachInfo) + (numLists * sizeof(ForeachVarList *))));
    dupPtr->numLists = numLists;
    dupPtr->firstValueTemp = srcPtr->firstValueTemp;
    dupPtr->loopCtTemp = srcPtr->loopCtTemp;
    
    for (i = 0;  i < numLists;  i++) {
	srcListPtr = srcPtr->varLists[i];
	numVars = srcListPtr->numVars;
	dupListPtr = (ForeachVarList *) ckalloc((unsigned)
	        sizeof(ForeachVarList) + numVars*sizeof(int));
	dupListPtr->numVars = numVars;
	for (j = 0;  j < numVars;  j++) {







|





|







1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
				 * auxiliary data to duplicate. */
{
    register ForeachInfo *srcPtr = (ForeachInfo *) clientData;
    ForeachInfo *dupPtr;
    register ForeachVarList *srcListPtr, *dupListPtr;
    int numLists = srcPtr->numLists;
    int numVars, i, j;

    dupPtr = (ForeachInfo *) ckalloc((unsigned)
	    (sizeof(ForeachInfo) + (numLists * sizeof(ForeachVarList *))));
    dupPtr->numLists = numLists;
    dupPtr->firstValueTemp = srcPtr->firstValueTemp;
    dupPtr->loopCtTemp = srcPtr->loopCtTemp;

    for (i = 0;  i < numLists;  i++) {
	srcListPtr = srcPtr->varLists[i];
	numVars = srcListPtr->numVars;
	dupListPtr = (ForeachVarList *) ckalloc((unsigned)
	        sizeof(ForeachVarList) + numVars*sizeof(int));
	dupListPtr->numVars = numVars;
	for (j = 0;  j < numVars;  j++) {
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
	    goto done;
	}

	/*
	 * Compile the test expression then emit the conditional jump
	 * around the "then" part. 
	 */
	
	envPtr->currStackDepth = savedStackDepth;
	testTokenPtr = tokenPtr;


	if (realCond) {
	    /*
	     * Find out if the condition is a constant. 
	     */
	
	    Tcl_Obj *boolObj = Tcl_NewStringObj(testTokenPtr[1].start,
		    testTokenPtr[1].size);
	    Tcl_IncrRefCount(boolObj);
	    code = Tcl_GetBooleanFromObj(NULL, boolObj, &boolVal);
	    Tcl_DecrRefCount(boolObj);
	    if (code == TCL_OK) {
		/*







|








|







1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
	    goto done;
	}

	/*
	 * Compile the test expression then emit the conditional jump
	 * around the "then" part. 
	 */

	envPtr->currStackDepth = savedStackDepth;
	testTokenPtr = tokenPtr;


	if (realCond) {
	    /*
	     * Find out if the condition is a constant. 
	     */

	    Tcl_Obj *boolObj = Tcl_NewStringObj(testTokenPtr[1].start,
		    testTokenPtr[1].size);
	    Tcl_IncrRefCount(boolObj);
	    code = Tcl_GetBooleanFromObj(NULL, boolObj, &boolVal);
	    Tcl_DecrRefCount(boolObj);
	    if (code == TCL_OK) {
		/*
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
	}

	if (realCond) {
	    /*
	     * Jump to the end of the "if" command. Both jumpFalseFixupArray and
	     * jumpEndFixupArray are indexed by "jumpIndex".
	     */
	    
	    if (jumpEndFixupArray.next >= jumpEndFixupArray.end) {
		TclExpandJumpFixupArray(&jumpEndFixupArray);
	    }
	    jumpEndFixupArray.next++;
	    TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
	            &(jumpEndFixupArray.fixup[jumpIndex]));
	    
	    /*
	     * Fix the target of the jumpFalse after the test. Generate a 4 byte
	     * jump if the distance is > 120 bytes. This is conservative, and
	     * ensures that we won't have to replace this jump if we later also
	     * need to replace the proceeding jump to the end of the "if" with a
	     * 4 byte jump.
	     */

	    if (TclFixupForwardJumpToHere(envPtr,
	            &(jumpFalseFixupArray.fixup[jumpIndex]), 120)) {
		/*
		 * Adjust the code offset for the proceeding jump to the end
		 * of the "if" command.
		 */
		
		jumpEndFixupArray.fixup[jumpIndex].codeOffset += 3;
	    }
	} else if (boolVal) {
	    /* 
	     *We were processing an "if 1 {...}"; stop compiling
	     * scripts
	     */







|






|














|







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
	}

	if (realCond) {
	    /*
	     * Jump to the end of the "if" command. Both jumpFalseFixupArray and
	     * jumpEndFixupArray are indexed by "jumpIndex".
	     */

	    if (jumpEndFixupArray.next >= jumpEndFixupArray.end) {
		TclExpandJumpFixupArray(&jumpEndFixupArray);
	    }
	    jumpEndFixupArray.next++;
	    TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP,
	            &(jumpEndFixupArray.fixup[jumpIndex]));

	    /*
	     * Fix the target of the jumpFalse after the test. Generate a 4 byte
	     * jump if the distance is > 120 bytes. This is conservative, and
	     * ensures that we won't have to replace this jump if we later also
	     * need to replace the proceeding jump to the end of the "if" with a
	     * 4 byte jump.
	     */

	    if (TclFixupForwardJumpToHere(envPtr,
	            &(jumpFalseFixupArray.fixup[jumpIndex]), 120)) {
		/*
		 * Adjust the code offset for the proceeding jump to the end
		 * of the "if" command.
		 */

		jumpEndFixupArray.fixup[jumpIndex].codeOffset += 3;
	    }
	} else if (boolVal) {
	    /* 
	     *We were processing an "if 1 {...}"; stop compiling
	     * scripts
	     */
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
	    }
	}

	if (compileScripts) {
	    /*
	     * Compile the else command body.
	     */
	    
	    code = TclCompileCmdWord(interp, tokenPtr+1,
		    tokenPtr->numComponents, envPtr);
	    if (code != TCL_OK) {
		if (code == TCL_ERROR) {
		    sprintf(buffer, "\n    (\"if\" else script line %d)",
			    interp->errorLine);
		    Tcl_AddObjErrorInfo(interp, buffer, -1);
		}
		goto done;
	    }
	}

	/*
	 * Make sure there are no words after the else clause.
	 */
	
	wordIdx++;
	if (wordIdx < numWords) {
	    Tcl_ResetResult(interp);
	    Tcl_AppendToObj(Tcl_GetObjResult(interp),
		    "wrong # args: extra words after \"else\" clause in \"if\" command", -1);
	    code = TCL_ERROR;
	    goto done;







|















|







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
	    }
	}

	if (compileScripts) {
	    /*
	     * Compile the else command body.
	     */

	    code = TclCompileCmdWord(interp, tokenPtr+1,
		    tokenPtr->numComponents, envPtr);
	    if (code != TCL_OK) {
		if (code == TCL_ERROR) {
		    sprintf(buffer, "\n    (\"if\" else script line %d)",
			    interp->errorLine);
		    Tcl_AddObjErrorInfo(interp, buffer, -1);
		}
		goto done;
	    }
	}

	/*
	 * Make sure there are no words after the else clause.
	 */

	wordIdx++;
	if (wordIdx < numWords) {
	    Tcl_ResetResult(interp);
	    Tcl_AppendToObj(Tcl_GetObjResult(interp),
		    "wrong # args: extra words after \"else\" clause in \"if\" command", -1);
	    code = TCL_ERROR;
	    goto done;
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
	    TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
	}
    }

    /*
     * Fix the unconditional jumps to the end of the "if" command.
     */
    
    for (j = jumpEndFixupArray.next;  j > 0;  j--) {
	jumpIndex = (j - 1);	/* i.e. process the closest jump first */
	if (TclFixupForwardJumpToHere(envPtr,
	        &(jumpEndFixupArray.fixup[jumpIndex]), 127)) {
	    /*
	     * Adjust the immediately preceeding "ifFalse" jump. We moved
	     * it's target (just after this jump) down three bytes.







|







1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
	    TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
	}
    }

    /*
     * Fix the unconditional jumps to the end of the "if" command.
     */

    for (j = jumpEndFixupArray.next;  j > 0;  j--) {
	jumpIndex = (j - 1);	/* i.e. process the closest jump first */
	if (TclFixupForwardJumpToHere(envPtr,
	        &(jumpEndFixupArray.fixup[jumpIndex]), 127)) {
	    /*
	     * Adjust the immediately preceeding "ifFalse" jump. We moved
	     * it's target (just after this jump) down three bytes.
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
		jumpFalseDist += 3;
		TclStoreInt1AtPtr(jumpFalseDist, (ifFalsePc + 1));
	    } else if (opCode == INST_JUMP_FALSE4) {
		jumpFalseDist = TclGetInt4AtPtr(ifFalsePc + 1);
		jumpFalseDist += 3;
		TclStoreInt4AtPtr(jumpFalseDist, (ifFalsePc + 1));
	    } else {
		panic("TclCompileIfCmd: unexpected opcode updating ifFalse jump");
	    }
	}
    }

    /*
     * Free the jumpFixupArray array if malloc'ed storage was used.
     */







|







1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
		jumpFalseDist += 3;
		TclStoreInt1AtPtr(jumpFalseDist, (ifFalsePc + 1));
	    } else if (opCode == INST_JUMP_FALSE4) {
		jumpFalseDist = TclGetInt4AtPtr(ifFalsePc + 1);
		jumpFalseDist += 3;
		TclStoreInt4AtPtr(jumpFalseDist, (ifFalsePc + 1));
	    } else {
		Tcl_Panic("TclCompileIfCmd: unexpected opcode updating ifFalse jump");
	    }
	}
    }

    /*
     * Free the jumpFixupArray array if malloc'ed storage was used.
     */
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
		goto done;
	    }
	}
    } else {			/* no incr amount given so use 1 */
	haveImmValue = 1;
	immValue = 1;
    }
    
    /*
     * Emit the instruction to increment the variable.
     */

    if (simpleVarName) {
	if (isScalar) {
	    if (localIndex >= 0) {







|







1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
		goto done;
	    }
	}
    } else {			/* no incr amount given so use 1 */
	haveImmValue = 1;
	immValue = 1;
    }

    /*
     * Emit the instruction to increment the variable.
     */

    if (simpleVarName) {
	if (isScalar) {
	    if (localIndex >= 0) {
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
    } else {			/* non-simple variable name */
	if (haveImmValue) {
	    TclEmitInstInt1(INST_INCR_STK_IMM, immValue, envPtr);
	} else {
	    TclEmitOpcode(INST_INCR_STK, envPtr);
	}
    }
	
    done:
    return code;
}

/*
 *----------------------------------------------------------------------
 *







|







1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
    } else {			/* non-simple variable name */
	if (haveImmValue) {
	    TclEmitInstInt1(INST_INCR_STK_IMM, immValue, envPtr);
	} else {
	    TclEmitOpcode(INST_INCR_STK, envPtr);
	}
    }

    done:
    return code;
}

/*
 *----------------------------------------------------------------------
 *
1739
1740
1741
1742
1743
1744
1745

























































































































1746
1747
1748
1749
1750
1751
1752
    done:
    return code;
}

/*
 *----------------------------------------------------------------------
 *

























































































































 * TclCompileLindexCmd --
 *
 *	Procedure called to compile the "lindex" command.
 *
 * Results:
 *	The return value is a standard Tcl result, which is TCL_OK if the
 *	compilation was successful.  If the command cannot be byte-compiled,







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







1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
    done:
    return code;
}

/*
 *----------------------------------------------------------------------
 *
 * TclCompileLassignCmd --
 *
 *	Procedure called to compile the "lassign" command.
 *
 * Results:
 *	The return value is a standard Tcl result, which is TCL_OK if the
 *	compilation was successful.  If the command cannot be byte-compiled,
 *	TCL_OUT_LINE_COMPILE is returned, indicating that the command should
 *	be compiled "out of line" by emitting code to invoke its command
 *	procedure (Tcl_LassignObjCmd) at runtime, which enforces in correct
 *	error handling.
 *
 * Side effects:
 *	Instructions are added to envPtr to execute the "lassign" command
 *	at runtime.
 *
 *----------------------------------------------------------------------
 */

int
TclCompileLassignCmd(interp, parsePtr, envPtr)
    Tcl_Interp *interp;		/* Used for error reporting. */
    Tcl_Parse *parsePtr;	/* Points to a parse structure for the
				 * command created by Tcl_ParseCommand. */
    CompileEnv *envPtr;		/* Holds resulting instructions. */
{
    Tcl_Token *tokenPtr;
    int simpleVarName, isScalar, localIndex, numWords, code, idx;

    numWords = parsePtr->numWords;
    /*
     * Check for command syntax error, but we'll punt that to runtime
     */
    if (numWords < 3) {
	return TCL_OUT_LINE_COMPILE;
    }

    /*
     * Generate code to push list being taken apart by [lassign].
     */
    tokenPtr = parsePtr->tokenPtr + (parsePtr->tokenPtr->numComponents + 1);
    if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
	TclEmitPush(TclRegisterNewLiteral(envPtr, 
		tokenPtr[1].start, tokenPtr[1].size), envPtr);
    } else {
	code = TclCompileTokens(interp, tokenPtr+1,
		tokenPtr->numComponents, envPtr);
	if (code != TCL_OK) {
	    return code;
	}
    }

    /*
     * Generate code to assign values from the list to variables
     */
    for (idx=0 ; idx<numWords-2 ; idx++) {
	tokenPtr += tokenPtr->numComponents + 1;

	/*
	 * Generate the next variable name
	 */
	code = TclPushVarName(interp, tokenPtr, envPtr, TCL_CREATE_VAR,
		&localIndex, &simpleVarName, &isScalar);
	if (code != TCL_OK) {
	    return code;
	}

	/*
	 * Emit instructions to get the idx'th item out of the list
	 * value on the stack and assign it to the variable.
	 */
	if (simpleVarName) {
	    if (isScalar) {
		if (localIndex >= 0) {
		    TclEmitOpcode(INST_DUP, envPtr);
		    TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
		    if (localIndex <= 255) {
			TclEmitInstInt1(INST_STORE_SCALAR1, localIndex, envPtr);
		    } else {
			TclEmitInstInt4(INST_STORE_SCALAR4, localIndex, envPtr);
		    }
		} else {
		    TclEmitInstInt4(INST_OVER, 1, envPtr);
		    TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
		    TclEmitOpcode(INST_STORE_SCALAR_STK, envPtr);
		}
	    } else {
		if (localIndex >= 0) {
		    TclEmitInstInt4(INST_OVER, 1, envPtr);
		    TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
		    if (localIndex <= 255) {
			TclEmitInstInt1(INST_STORE_ARRAY1, localIndex, envPtr);
		    } else {
			TclEmitInstInt4(INST_STORE_ARRAY4, localIndex, envPtr);
		    }
		} else {
		    TclEmitInstInt4(INST_OVER, 2, envPtr);
		    TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
		    TclEmitOpcode(INST_STORE_ARRAY_STK, envPtr);
		}
	    }
	} else {
	    TclEmitInstInt4(INST_OVER, 1, envPtr);
	    TclEmitInstInt4(INST_LIST_INDEX_IMM, idx, envPtr);
	    TclEmitOpcode(INST_STORE_STK, envPtr);
	}
	TclEmitOpcode(INST_POP, envPtr);
    }

    /*
     * Generate code to leave the rest of the list on the stack.
     */
    TclEmitInstInt4(INST_LIST_RANGE_IMM, idx, envPtr);
    TclEmitInt4(-2, envPtr); /* -2 == "end" */

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclCompileLindexCmd --
 *
 *	Procedure called to compile the "lindex" command.
 *
 * Results:
 *	The return value is a standard Tcl result, which is TCL_OK if the
 *	compilation was successful.  If the command cannot be byte-compiled,
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
    int numWords;
    numWords = parsePtr->numWords;

    /*
     * Quit if too few args
     */

    if ( numWords <= 1 ) {
	return TCL_OUT_LINE_COMPILE;
    }

    varTokenPtr = parsePtr->tokenPtr
	+ (parsePtr->tokenPtr->numComponents + 1);
    
    /*
     * Push the operands onto the stack.
     */
	
    for ( i = 1 ; i < numWords ; i++ ) {
	if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
	    TclEmitPush(
		    TclRegisterNewLiteral( envPtr, varTokenPtr[1].start,
		    varTokenPtr[1].size), envPtr);
	} else {
	    code = TclCompileTokens(interp, varTokenPtr+1,
				    varTokenPtr->numComponents, envPtr);
	    if (code != TCL_OK) {
		return code;
	    }
	}
	varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
    }
	
    /*
     * Emit INST_LIST_INDEX if objc==3, or INST_LIST_INDEX_MULTI
     * if there are multiple index args.
     */

    if ( numWords == 3 ) {
	TclEmitOpcode( INST_LIST_INDEX, envPtr );
    } else {
 	TclEmitInstInt4( INST_LIST_INDEX_MULTI, numWords-1, envPtr );
    }

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------







|





|



|
|


|



|






|





|
|

|







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
    int numWords;
    numWords = parsePtr->numWords;

    /*
     * Quit if too few args
     */

    if (numWords <= 1) {
	return TCL_OUT_LINE_COMPILE;
    }

    varTokenPtr = parsePtr->tokenPtr
	+ (parsePtr->tokenPtr->numComponents + 1);

    /*
     * Push the operands onto the stack.
     */

    for (i=1 ; i<numWords ; i++) {
	if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
	    TclEmitPush(
		    TclRegisterNewLiteral(envPtr, varTokenPtr[1].start,
		    varTokenPtr[1].size), envPtr);
	} else {
	    code = TclCompileTokens(interp, varTokenPtr+1,
		    varTokenPtr->numComponents, envPtr);
	    if (code != TCL_OK) {
		return code;
	    }
	}
	varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);
    }

    /*
     * Emit INST_LIST_INDEX if objc==3, or INST_LIST_INDEX_MULTI
     * if there are multiple index args.
     */

    if (numWords == 3) {
	TclEmitOpcode(INST_LIST_INDEX, envPtr);
    } else {
 	TclEmitInstInt4(INST_LIST_INDEX_MULTI, numWords-1, envPtr);
    }

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
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
 *	(7) Finally, INST_STORE_* stores the new value in the variable
 *	    and cleans up the stack.
 *
 *----------------------------------------------------------------------
 */

int
TclCompileLsetCmd( interp, parsePtr, envPtr )
    Tcl_Interp* interp;		/* Tcl interpreter for error reporting */
    Tcl_Parse* parsePtr;	/* Points to a parse structure for
				 * the command */
    CompileEnv* envPtr;		/* Holds the resulting instructions */
{

    int tempDepth;		/* Depth used for emitting one part
				 * of the code burst. */
    Tcl_Token* varTokenPtr;	/* Pointer to the Tcl_Token representing
				 * the parse of the variable name */

    int result;			/* Status return from library calls */

    int localIndex;		/* Index of var in local var table */
    int simpleVarName;		/* Flag == 1 if var name is simple */
    int isScalar;		/* Flag == 1 if scalar, 0 if array */

    int i;

    /* Check argument count */

    if ( parsePtr->numWords < 3 ) {
	/* Fail at run time, not in compilation */
	return TCL_OUT_LINE_COMPILE;
    }

    /*
     * Decide if we can use a frame slot for the var/array name or if we
     * need to emit code to compute and push the name at runtime. We use a
     * frame slot (entry in the array of local vars) if we are compiling a
     * procedure body and if the name is simple text that does not include
     * namespace qualifiers. 
     */

    varTokenPtr = parsePtr->tokenPtr
	    + (parsePtr->tokenPtr->numComponents + 1);
    result = TclPushVarName( interp, varTokenPtr, envPtr, 
            TCL_CREATE_VAR, &localIndex, &simpleVarName, &isScalar );
    if (result != TCL_OK) {
	return result;
    }

    /* Push the "index" args and the new element value. */

    for ( i = 2; i < parsePtr->numWords; ++i ) {

	/* Advance to next arg */

	varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);

	/* Push an arg */

	if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
	    TclEmitPush(TclRegisterNewLiteral( envPtr, varTokenPtr[1].start,
		    varTokenPtr[1].size), envPtr);
	} else {
	    result = TclCompileTokens(interp, varTokenPtr+1,
				      varTokenPtr->numComponents, envPtr);
	    if ( result != TCL_OK ) {
		return result;
	    }
	}
    }

    /*
     * Duplicate the variable name if it's been pushed.  
     */

    if ( !simpleVarName || localIndex < 0 ) {
	if ( !simpleVarName || isScalar ) {
	    tempDepth = parsePtr->numWords - 2;
	} else {
	    tempDepth = parsePtr->numWords - 1;
	}
	TclEmitInstInt4( INST_OVER, tempDepth, envPtr );
    }

    /*
     * Duplicate an array index if one's been pushed
     */

    if ( simpleVarName && !isScalar ) {
	if ( localIndex < 0 ) {
	    tempDepth = parsePtr->numWords - 1;
	} else {
	    tempDepth = parsePtr->numWords - 2;
	}
	TclEmitInstInt4( INST_OVER, tempDepth, envPtr );
    }

    /*
     * Emit code to load the variable's value.
     */

    if ( !simpleVarName ) {
	TclEmitOpcode( INST_LOAD_STK, envPtr );
    } else if ( isScalar ) {
	if ( localIndex < 0 ) {
	    TclEmitOpcode( INST_LOAD_SCALAR_STK, envPtr );
	} else if ( localIndex < 0x100 ) {
	    TclEmitInstInt1( INST_LOAD_SCALAR1, localIndex, envPtr );
	} else {
	    TclEmitInstInt4( INST_LOAD_SCALAR4, localIndex, envPtr );
	}
    } else {
	if ( localIndex < 0 ) {
	    TclEmitOpcode( INST_LOAD_ARRAY_STK, envPtr );
	} else if ( localIndex < 0x100 ) {
	    TclEmitInstInt1( INST_LOAD_ARRAY1, localIndex, envPtr );
	} else {
	    TclEmitInstInt4( INST_LOAD_ARRAY4, localIndex, envPtr );
	}
    }

    /*
     * Emit the correct variety of 'lset' instruction
     */

    if ( parsePtr->numWords == 4 ) {
	TclEmitOpcode( INST_LSET_LIST, envPtr );
    } else {
	TclEmitInstInt4( INST_LSET_FLAT, (parsePtr->numWords - 1), envPtr );
    }

    /*
     * Emit code to put the value back in the variable
     */

    if ( !simpleVarName ) {
	TclEmitOpcode( INST_STORE_STK, envPtr );
    } else if ( isScalar ) {
	if ( localIndex < 0 ) {
	    TclEmitOpcode( INST_STORE_SCALAR_STK, envPtr );
	} else if ( localIndex < 0x100 ) {
	    TclEmitInstInt1( INST_STORE_SCALAR1, localIndex, envPtr );
	} else {
	    TclEmitInstInt4( INST_STORE_SCALAR4, localIndex, envPtr );
	}
    } else {
	if ( localIndex < 0 ) {
	    TclEmitOpcode( INST_STORE_ARRAY_STK, envPtr );
	} else if ( localIndex < 0x100 ) {
	    TclEmitInstInt1( INST_STORE_ARRAY1, localIndex, envPtr );
	} else {
	    TclEmitInstInt4( INST_STORE_ARRAY4, localIndex, envPtr );
	}
    }
    
    return TCL_OK;

}

/*
 *----------------------------------------------------------------------
 *
 * TclCompileRegexpCmd --
 *







|





<




<

<



<




|














|
|






|
<







|



|
|









|
|




|






|
|




|






|
|
|
|
|
|
|

|


|
|
|
|

|







|
|

|






|
|
|
|
|
|
|

|


|
|
|
|

|


|

<







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
 *	(7) Finally, INST_STORE_* stores the new value in the variable
 *	    and cleans up the stack.
 *
 *----------------------------------------------------------------------
 */

int
TclCompileLsetCmd(interp, parsePtr, envPtr)
    Tcl_Interp* interp;		/* Tcl interpreter for error reporting */
    Tcl_Parse* parsePtr;	/* Points to a parse structure for
				 * the command */
    CompileEnv* envPtr;		/* Holds the resulting instructions */
{

    int tempDepth;		/* Depth used for emitting one part
				 * of the code burst. */
    Tcl_Token* varTokenPtr;	/* Pointer to the Tcl_Token representing
				 * the parse of the variable name */

    int result;			/* Status return from library calls */

    int localIndex;		/* Index of var in local var table */
    int simpleVarName;		/* Flag == 1 if var name is simple */
    int isScalar;		/* Flag == 1 if scalar, 0 if array */

    int i;

    /* Check argument count */

    if (parsePtr->numWords < 3) {
	/* Fail at run time, not in compilation */
	return TCL_OUT_LINE_COMPILE;
    }

    /*
     * Decide if we can use a frame slot for the var/array name or if we
     * need to emit code to compute and push the name at runtime. We use a
     * frame slot (entry in the array of local vars) if we are compiling a
     * procedure body and if the name is simple text that does not include
     * namespace qualifiers. 
     */

    varTokenPtr = parsePtr->tokenPtr
	    + (parsePtr->tokenPtr->numComponents + 1);
    result = TclPushVarName(interp, varTokenPtr, envPtr, TCL_CREATE_VAR,
	    &localIndex, &simpleVarName, &isScalar);
    if (result != TCL_OK) {
	return result;
    }

    /* Push the "index" args and the new element value. */

    for (i=2 ; i<parsePtr->numWords ; ++i) {

	/* Advance to next arg */

	varTokenPtr = varTokenPtr + (varTokenPtr->numComponents + 1);

	/* Push an arg */

	if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
	    TclEmitPush(TclRegisterNewLiteral(envPtr, varTokenPtr[1].start,
		    varTokenPtr[1].size), envPtr);
	} else {
	    result = TclCompileTokens(interp, varTokenPtr+1,
		    varTokenPtr->numComponents, envPtr);
	    if (result != TCL_OK) {
		return result;
	    }
	}
    }

    /*
     * Duplicate the variable name if it's been pushed.  
     */

    if (!simpleVarName || localIndex < 0) {
	if (!simpleVarName || isScalar) {
	    tempDepth = parsePtr->numWords - 2;
	} else {
	    tempDepth = parsePtr->numWords - 1;
	}
	TclEmitInstInt4(INST_OVER, tempDepth, envPtr);
    }

    /*
     * Duplicate an array index if one's been pushed
     */

    if (simpleVarName && !isScalar) {
	if (localIndex < 0) {
	    tempDepth = parsePtr->numWords - 1;
	} else {
	    tempDepth = parsePtr->numWords - 2;
	}
	TclEmitInstInt4(INST_OVER, tempDepth, envPtr);
    }

    /*
     * Emit code to load the variable's value.
     */

    if (!simpleVarName) {
	TclEmitOpcode(INST_LOAD_STK, envPtr);
    } else if (isScalar) {
	if (localIndex < 0) {
	    TclEmitOpcode(INST_LOAD_SCALAR_STK, envPtr);
	} else if (localIndex < 0x100) {
	    TclEmitInstInt1(INST_LOAD_SCALAR1, localIndex, envPtr);
	} else {
	    TclEmitInstInt4(INST_LOAD_SCALAR4, localIndex, envPtr);
	}
    } else {
	if (localIndex < 0) {
	    TclEmitOpcode(INST_LOAD_ARRAY_STK, envPtr);
	} else if (localIndex < 0x100) {
	    TclEmitInstInt1(INST_LOAD_ARRAY1, localIndex, envPtr);
	} else {
	    TclEmitInstInt4(INST_LOAD_ARRAY4, localIndex, envPtr);
	}
    }

    /*
     * Emit the correct variety of 'lset' instruction
     */

    if (parsePtr->numWords == 4) {
	TclEmitOpcode(INST_LSET_LIST, envPtr);
    } else {
	TclEmitInstInt4(INST_LSET_FLAT, (parsePtr->numWords - 1), envPtr);
    }

    /*
     * Emit code to put the value back in the variable
     */

    if (!simpleVarName) {
	TclEmitOpcode(INST_STORE_STK, envPtr);
    } else if (isScalar) {
	if (localIndex < 0) {
	    TclEmitOpcode(INST_STORE_SCALAR_STK, envPtr);
	} else if (localIndex < 0x100) {
	    TclEmitInstInt1(INST_STORE_SCALAR1, localIndex, envPtr);
	} else {
	    TclEmitInstInt4(INST_STORE_SCALAR4, localIndex, envPtr);
	}
    } else {
	if (localIndex < 0) {
	    TclEmitOpcode(INST_STORE_ARRAY_STK, envPtr);
	} else if (localIndex < 0x100) {
	    TclEmitInstInt1(INST_STORE_ARRAY1, localIndex, envPtr);
	} else {
	    TclEmitInstInt4(INST_STORE_ARRAY4, localIndex, envPtr);
	}
    }

    return TCL_OK;

}

/*
 *----------------------------------------------------------------------
 *
 * TclCompileRegexpCmd --
 *
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
 *
 * TclCompileReturnCmd --
 *
 *	Procedure called to compile the "return" command.
 *
 * Results:
 *	The return value is a standard Tcl result, which is TCL_OK if the
 *	compilation was successful.  If the particular return command is
 *	too complex for this function (ie, return with any flags like "-code"
 *	or "-errorinfo"), TCL_OUT_LINE_COMPILE is returned, indicating that
 *	the command should be compiled "out of line" (eg, not byte compiled).
 *	If an error occurs then the interpreter's result contains a standard
 *	error message.
 *
 * Side effects:
 *	Instructions are added to envPtr to execute the "return" command
 *	at runtime.
 *
 *----------------------------------------------------------------------
 */

int
TclCompileReturnCmd(interp, parsePtr, envPtr)
    Tcl_Interp *interp;		/* Used for error reporting. */
    Tcl_Parse *parsePtr;	/* Points to a parse structure for the
				 * command created by Tcl_ParseCommand. */
    CompileEnv *envPtr;		/* Holds resulting instructions. */
{
    Tcl_Token *varTokenPtr;
    int code;

    switch (parsePtr->numWords) {
	case 1: {
	    /*
	     * Simple case:  [return]
	     * Just push the literal string "".

	     */
	    TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
	    break;
	}

	case 2: {
	    /*
	     * More complex cases:



	     * [return "foo"]
	     * [return $value]
	     * [return [otherCmd]]
	     */
	    varTokenPtr = parsePtr->tokenPtr
		+ (parsePtr->tokenPtr->numComponents + 1);
	    if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {

		/*
		 * [return "foo"] case:  the parse token is a simple word,
		 * so just push it.


		 */
		TclEmitPush(TclRegisterNewLiteral(envPtr, varTokenPtr[1].start,
			varTokenPtr[1].size), envPtr);
	    } else {
		/*
		 * Parse token is more complex, so compile it; this handles the
		 * variable reference and nested command cases.  If the
		 * parse token can be byte-compiled, then this instance of
		 * "return" will be byte-compiled; otherwise it will be
		 * out line compiled.
		 */
		code = TclCompileTokens(interp, varTokenPtr+1,

			varTokenPtr->numComponents, envPtr);

		if (code != TCL_OK) {
		    return code;
		}

	    }


	    break;


	}
	default: {
	    /*


	     * Most complex return cases: everything else, including
	     * [return -code error], etc.
	     */


	    return TCL_OUT_LINE_COMPILE;
	}
    }
























    /*
     * The INST_RETURN opcode triggers the branching out of the
     * subroutine, and takes the top stack item as the return result
     * (which is why we pushed the value above).


     */

















    TclEmitOpcode(INST_RETURN, envPtr);













    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclCompileSetCmd --







|
|
|
<
<
<















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

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

<
<
>
>
|
|
<
>
>




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

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







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
 *
 * TclCompileReturnCmd --
 *
 *	Procedure called to compile the "return" command.
 *
 * Results:
 *	The return value is a standard Tcl result, which is TCL_OK if the
 *	compilation was successful.  If analysis concludes that the
 *	command cannot be bytecompiled effectively, a return code of
 *	TCL__OUT_LINE_COMPILE is returned.



 *
 * Side effects:
 *	Instructions are added to envPtr to execute the "return" command
 *	at runtime.
 *
 *----------------------------------------------------------------------
 */

int
TclCompileReturnCmd(interp, parsePtr, envPtr)
    Tcl_Interp *interp;		/* Used for error reporting. */
    Tcl_Parse *parsePtr;	/* Points to a parse structure for the
				 * command created by Tcl_ParseCommand. */
    CompileEnv *envPtr;		/* Holds resulting instructions. */
{





    /*
     * General syntax: [return ?-option value ...? ?result?]

     * An even number of words means an explicit result argument is present.
     */



    int level = 1, code = TCL_OK, status = TCL_OK;
    int numWords = parsePtr->numWords;


    int explicitResult = (0 == (numWords % 2));
    int numOptionWords = numWords - 1 - explicitResult;
    Interp *iPtr = (Interp *) interp;
    Tcl_Obj *returnOpts = iPtr->defaultReturnOpts;



    Tcl_Token *wordTokenPtr = parsePtr->tokenPtr
		+ (parsePtr->tokenPtr->numComponents + 1);

    if (numOptionWords > 0) {
	/* 

	 * Scan through the return options.  If any are unknown at compile
	 * time, there is no value in bytecompiling.  Save the option values
	 * known in an objv array for merging into a return options dictionary.
	 */


	int objc;
	Tcl_Obj **objv = (Tcl_Obj **)
		ckalloc(numOptionWords * sizeof(Tcl_Obj *));
	for (objc = 0; objc < numOptionWords; objc++) {




	    objv[objc] = Tcl_NewObj();
	    Tcl_IncrRefCount(objv[objc]);
	    if (!TclWordKnownAtCompileTime(wordTokenPtr, objv[objc])) {
		objc++;
		status = TCL_ERROR;
		goto cleanup;
	    }
	    wordTokenPtr += wordTokenPtr->numComponents + 1;
	}
	status = TclMergeReturnOptions(interp, objc, objv,
		&returnOpts, &code, &level);
    cleanup:
	while (--objc >= 0) {
	    Tcl_DecrRefCount(objv[objc]);
	}


	ckfree((char *)objv);
	if (TCL_ERROR == status) {
	    /* Something was bogus in the return options.  Clear the
	     * error message, and report back to the compiler that this

	     * must be interpreted at runtime. */
	    Tcl_ResetResult(interp);
	    return TCL_OUT_LINE_COMPILE;
	}
    }

    /* All options are known at compile time, so we're going to
     * bytecompile.   Emit instructions to push the result on
     * the stack */

    if (explicitResult) {
	if (wordTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
	    /* Explicit result is a simple word, so we can compile quickly to
	     * a simple push */
	    TclEmitPush(TclRegisterNewLiteral(envPtr, wordTokenPtr[1].start,
			wordTokenPtr[1].size), envPtr);
	} else {
	    /* More complex tokens get compiled */
	    status = TclCompileTokens(interp, wordTokenPtr+1,
		    wordTokenPtr->numComponents, envPtr);
	    if (TCL_OK != status) {
		return status;
	    }
	}
    } else {
	/* No explict result argument, so default result is empty string */
	TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
    }

    /* 

     * Check for optimization:  When [return] is in a proc, and there's
     * no enclosing [catch], and the default return options are in effect,
     * then the INST_DONE instruction is equivalent, and considerably more
     * efficient.
     */
    if (returnOpts == iPtr->defaultReturnOpts) {
	/* We have default return options... */
	if (envPtr->procPtr != NULL) {
	    /* ... and we're in a proc ... */
	    int index = envPtr->exceptArrayNext - 1;
	    int enclosingCatch = 0;
	    while (index >= 0) {
		ExceptionRange range = envPtr->exceptArrayPtr[index];
		if ((range.type == CATCH_EXCEPTION_RANGE)
			&& (range.catchOffset == -1)) {
		    enclosingCatch = 1;
		    break;
		}
		index--;
	    }
	    if (!enclosingCatch) {
		/* ... and there is no enclosing catch. */
		TclEmitOpcode(INST_DONE, envPtr);
		return TCL_OK;
	    }
	}
    }

    /*
     * Could not use the optimization, so we push the return options
     * dictionary, and emit the INST_RETURN instruction with code
     * and level as operands.
     */
    TclEmitPush(TclAddLiteralObj(envPtr, returnOpts, NULL), envPtr);
    TclEmitInstInt4(INST_RETURN, code, envPtr);
    TclEmitInt4(level, envPtr);
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * TclCompileSetCmd --
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
		TclEmitOpcode((isAssignment?
		        INST_STORE_ARRAY_STK : INST_LOAD_ARRAY_STK), envPtr);
	    }
	}
    } else {
	TclEmitOpcode((isAssignment? INST_STORE_STK : INST_LOAD_STK), envPtr);
    }
	
    done:
    return code;
}

/*
 *----------------------------------------------------------------------
 *







|







2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
		TclEmitOpcode((isAssignment?
		        INST_STORE_ARRAY_STK : INST_LOAD_ARRAY_STK), envPtr);
	    }
	}
    } else {
	TclEmitOpcode((isAssignment? INST_STORE_STK : INST_LOAD_STK), envPtr);
    }

    done:
    return code;
}

/*
 *----------------------------------------------------------------------
 *
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
				 * command created by Tcl_ParseCommand. */
    CompileEnv *envPtr;		/* Holds resulting instructions. */
{
    Tcl_Token *opTokenPtr, *varTokenPtr;
    Tcl_Obj *opObj;
    int index;
    int code;
    
    static CONST char *options[] = {
	"bytelength",	"compare",	"equal",	"first",
	"index",	"is",		"last",		"length",
	"map",		"match",	"range",	"repeat",
	"replace",	"tolower",	"toupper",	"totitle",
	"trim",		"trimleft",	"trimright",
	"wordend",	"wordstart",	(char *) NULL







|







2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
				 * command created by Tcl_ParseCommand. */
    CompileEnv *envPtr;		/* Holds resulting instructions. */
{
    Tcl_Token *opTokenPtr, *varTokenPtr;
    Tcl_Obj *opObj;
    int index;
    int code;

    static CONST char *options[] = {
	"bytelength",	"compare",	"equal",	"first",
	"index",	"is",		"last",		"length",
	"map",		"match",	"range",	"repeat",
	"replace",	"tolower",	"toupper",	"totitle",
	"trim",		"trimleft",	"trimright",
	"wordend",	"wordstart",	(char *) NULL
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
    /*
     * Generate a test for each arm.
     */

    contFixIndex = -1;
    fixupArray = (JumpFixup *) ckalloc(sizeof(JumpFixup) * argc);
    fixupTargetArray = (int *) ckalloc(sizeof(int) * argc);
    (VOID *) memset( fixupTargetArray, 0, argc * sizeof( int ) );
    fixupCount = 0;
    foundDefault = 0;
    for (i=0 ; i<argc ; i+=2) {
	int code;		/* Return codes from sub-compiles. */
	int nextArmFixupIndex = -1;

	/*







|







3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
    /*
     * Generate a test for each arm.
     */

    contFixIndex = -1;
    fixupArray = (JumpFixup *) ckalloc(sizeof(JumpFixup) * argc);
    fixupTargetArray = (int *) ckalloc(sizeof(int) * argc);
    (VOID *) memset(fixupTargetArray, 0, argc * sizeof(int));
    fixupCount = 0;
    foundDefault = 0;
    for (i=0 ; i<argc ; i+=2) {
	int code;		/* Return codes from sub-compiles. */
	int nextArmFixupIndex = -1;

	/*
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
	    case Switch_Glob:
		TclEmitPush(TclRegisterNewLiteral(envPtr, argv[i],
			(int) strlen(argv[i])), envPtr);
		TclEmitInstInt4(INST_OVER, 1, envPtr);
		TclEmitInstInt1(INST_STR_MATCH, /*nocase*/0, envPtr);
		break;
	    default:
		panic("unknown switch mode: %d",mode);
	    }
	    /*
	     * Process fall-through clauses here...
	     */
	    if (argv[i+1][0]=='-' && argv[i+1][1]=='\0') {
		if (contFixIndex == -1) {
		    contFixIndex = fixupCount;







|







3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
	    case Switch_Glob:
		TclEmitPush(TclRegisterNewLiteral(envPtr, argv[i],
			(int) strlen(argv[i])), envPtr);
		TclEmitInstInt4(INST_OVER, 1, envPtr);
		TclEmitInstInt1(INST_STR_MATCH, /*nocase*/0, envPtr);
		break;
	    default:
		Tcl_Panic("unknown switch mode: %d",mode);
	    }
	    /*
	     * Process fall-through clauses here...
	     */
	    if (argv[i+1][0]=='-' && argv[i+1][1]=='\0') {
		if (contFixIndex == -1) {
		    contFixIndex = fixupCount;
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
    Tcl_Parse *parsePtr;	/* Points to a parse structure for the
				 * command created by Tcl_ParseCommand. */
    CompileEnv *envPtr;		/* Holds resulting instructions. */
{
    Tcl_Token *varTokenPtr;
    int i, numWords;
    CONST char *varName, *tail;
    
    if (envPtr->procPtr == NULL) {
	return TCL_OUT_LINE_COMPILE;
    }

    numWords = parsePtr->numWords;
    
    varTokenPtr = parsePtr->tokenPtr
	+ (parsePtr->tokenPtr->numComponents + 1);
    for (i = 1; i < numWords; i += 2) {
	if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
	    varName = varTokenPtr[1].start;
	    tail = varName + varTokenPtr[1].size - 1;
	    if ((*tail == ')') || (tail < varName)) continue;







|





|







3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
    Tcl_Parse *parsePtr;	/* Points to a parse structure for the
				 * command created by Tcl_ParseCommand. */
    CompileEnv *envPtr;		/* Holds resulting instructions. */
{
    Tcl_Token *varTokenPtr;
    int i, numWords;
    CONST char *varName, *tail;

    if (envPtr->procPtr == NULL) {
	return TCL_OUT_LINE_COMPILE;
    }

    numWords = parsePtr->numWords;

    varTokenPtr = parsePtr->tokenPtr
	+ (parsePtr->tokenPtr->numComponents + 1);
    for (i = 1; i < numWords; i += 2) {
	if (varTokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
	    varName = varTokenPtr[1].start;
	    tail = varName + varTokenPtr[1].size - 1;
	    if ((*tail == ')') || (tail < varName)) continue;
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380

    if (loopMayEnd) {
	TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpEvalCondFixup);
	testCodeOffset = 0; /* avoid compiler warning */
    } else {
	testCodeOffset = (envPtr->codeNext - envPtr->codeStart);
    }
    

    /*
     * Compile the loop body.
     */

    bodyCodeOffset = (envPtr->codeNext - envPtr->codeStart);
    code = TclCompileCmdWord(interp, bodyTokenPtr+1,







<







3527
3528
3529
3530
3531
3532
3533

3534
3535
3536
3537
3538
3539
3540

    if (loopMayEnd) {
	TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &jumpEvalCondFixup);
	testCodeOffset = 0; /* avoid compiler warning */
    } else {
	testCodeOffset = (envPtr->codeNext - envPtr->codeStart);
    }


    /*
     * Compile the loop body.
     */

    bodyCodeOffset = (envPtr->codeNext - envPtr->codeStart);
    code = TclCompileCmdWord(interp, bodyTokenPtr+1,
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
	    if (code == TCL_ERROR) {
		Tcl_AddObjErrorInfo(interp,
				    "\n    (\"while\" test expression)", -1);
	    }
	    goto error;
	}
	envPtr->currStackDepth = savedStackDepth + 1;
    
	jumpDist = (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset;
	if (jumpDist > 127) {
	    TclEmitInstInt4(INST_JUMP_TRUE4, -jumpDist, envPtr);
	} else {
	    TclEmitInstInt1(INST_JUMP_TRUE1, -jumpDist, envPtr);
	}
    } else {







|







3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
	    if (code == TCL_ERROR) {
		Tcl_AddObjErrorInfo(interp,
				    "\n    (\"while\" test expression)", -1);
	    }
	    goto error;
	}
	envPtr->currStackDepth = savedStackDepth + 1;

	jumpDist = (envPtr->codeNext - envPtr->codeStart) - bodyCodeOffset;
	if (jumpDist > 127) {
	    TclEmitInstInt4(INST_JUMP_TRUE4, -jumpDist, envPtr);
	} else {
	    TclEmitInstInt1(INST_JUMP_TRUE1, -jumpDist, envPtr);
	}
    } else {
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
     * Set the loop's body, continue and break offsets.
     */

    envPtr->exceptArrayPtr[range].continueOffset = testCodeOffset;
    envPtr->exceptArrayPtr[range].codeOffset = bodyCodeOffset;
    envPtr->exceptArrayPtr[range].breakOffset =
	    (envPtr->codeNext - envPtr->codeStart);
    
    /*
     * The while command's result is an empty string.
     */

    pushResult:
    envPtr->currStackDepth = savedStackDepth;
    TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);







|







3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
     * Set the loop's body, continue and break offsets.
     */

    envPtr->exceptArrayPtr[range].continueOffset = testCodeOffset;
    envPtr->exceptArrayPtr[range].codeOffset = bodyCodeOffset;
    envPtr->exceptArrayPtr[range].breakOffset =
	    (envPtr->codeNext - envPtr->codeStart);

    /*
     * The while command's result is an empty string.
     */

    pushResult:
    envPtr->currStackDepth = savedStackDepth;
    TclEmitPush(TclRegisterNewLiteral(envPtr, "", 0), envPtr);
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
	 * A simple variable name. Divide it up into "name" and "elName"
	 * strings. If it is not a local variable, look it up at runtime.
	 */
	simpleVarName = 1;

	name = varTokenPtr[1].start;
	nameChars = varTokenPtr[1].size;
	if ( *(name + nameChars - 1) == ')') {
	    /* 
	     * last char is ')' => potential array reference.
	     */

	    for (i = 0, p = name;  i < nameChars;  i++, p++) {
		if (*p == '(') {
		    elName = p + 1;
		    elNameChars = nameChars - i - 2;
		    nameChars = i ;
		    break;
		}
	    }

	    if ((elName != NULL) && elNameChars) {
		/*
		 * An array element, the element name is a simple







|




|



|







3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
	 * A simple variable name. Divide it up into "name" and "elName"
	 * strings. If it is not a local variable, look it up at runtime.
	 */
	simpleVarName = 1;

	name = varTokenPtr[1].start;
	nameChars = varTokenPtr[1].size;
	if (name[nameChars-1] == ')') {
	    /* 
	     * last char is ')' => potential array reference.
	     */

	    for (i=0,p=name ; i<nameChars ; i++,p++) {
		if (*p == '(') {
		    elName = p + 1;
		    elNameChars = nameChars - i - 2;
		    nameChars = i;
		    break;
		}
	    }

	    if ((elName != NULL) && elNameChars) {
		/*
		 * An array element, the element name is a simple
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
		elemTokenPtr = (Tcl_Token *) ckalloc(n * sizeof(Tcl_Token));
		allocedTokens = 1;
		elemTokenPtr->type = TCL_TOKEN_TEXT;
		elemTokenPtr->start = elName;
		elemTokenPtr->size = remainingChars;
		elemTokenPtr->numComponents = 0;
		elemTokenCount = n;
		
		/*
		 * Copy the remaining tokens.
		 */
		
		memcpy((void *) (elemTokenPtr+1), (void *) (&varTokenPtr[2]),
		       ((n-1) * sizeof(Tcl_Token)));
	    } else {
		/*
		 * Use the already available tokens.
		 */
		
		elemTokenPtr = &varTokenPtr[2];
		elemTokenCount = n - 1;	    
	    }
	}
    }

    if (simpleVarName) {







|



|

|




|







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
		elemTokenPtr = (Tcl_Token *) ckalloc(n * sizeof(Tcl_Token));
		allocedTokens = 1;
		elemTokenPtr->type = TCL_TOKEN_TEXT;
		elemTokenPtr->start = elName;
		elemTokenPtr->size = remainingChars;
		elemTokenPtr->numComponents = 0;
		elemTokenCount = n;

		/*
		 * Copy the remaining tokens.
		 */

		memcpy((void *) (elemTokenPtr+1), (void *) (&varTokenPtr[2]),
			((n-1) * sizeof(Tcl_Token)));
	    } else {
		/*
		 * Use the already available tokens.
		 */

		elemTokenPtr = &varTokenPtr[2];
		elemTokenCount = n - 1;	    
	    }
	}
    }

    if (simpleVarName) {
Changes to generic/tclCompExpr.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclCompExpr.c --
 *
 *	This file contains the code to compile Tcl expressions.
 *
 * Copyright (c) 1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 by Scriptics Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclCompExpr.c,v 1.14.2.2 2003/10/16 02:28:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"

/*
 * The stuff below is a bit of a hack so that this file can be used in











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclCompExpr.c --
 *
 *	This file contains the code to compile Tcl expressions.
 *
 * Copyright (c) 1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 by Scriptics Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclCompExpr.c,v 1.14.2.3 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"

/*
 * The stuff below is a bit of a hack so that this file can be used in
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
    Tcl_HashEntry *hPtr;
    CONST char *operator;
    Tcl_DString opBuf;
    int objIndex, opIndex, length, code;
    char buffer[TCL_UTF_MAX];

    if (exprTokenPtr->type != TCL_TOKEN_SUB_EXPR) {
	panic("CompileSubExpr: token type %d not TCL_TOKEN_SUB_EXPR\n",
	        exprTokenPtr->type);
    }
    code = TCL_OK;

    /*
     * Switch on the type of the first token after the subexpression token.
     * After processing it, advance tokenPtr to point just after the







|







347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
    Tcl_HashEntry *hPtr;
    CONST char *operator;
    Tcl_DString opBuf;
    int objIndex, opIndex, length, code;
    char buffer[TCL_UTF_MAX];

    if (exprTokenPtr->type != TCL_TOKEN_SUB_EXPR) {
	Tcl_Panic("CompileSubExpr: token type %d not TCL_TOKEN_SUB_EXPR\n",
	        exprTokenPtr->type);
    }
    code = TCL_OK;

    /*
     * Switch on the type of the first token after the subexpression token.
     * After processing it, advance tokenPtr to point just after the
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
		    if (code != TCL_OK) {
			goto done;
		    }
		    tokenPtr = endPtr;
		    break;
		    
		default:
		    panic("CompileSubExpr: unexpected operator %d requiring special treatment\n",
		        opIndex);
	    } /* end switch on operator requiring special treatment */
	    infoPtr->hasOperators = 1;
	    break;

        default:
	    panic("CompileSubExpr: unexpected token type %d\n",
	            tokenPtr->type);
    }

    /*
     * Verify that the subexpression token had the required number of
     * subtokens: that we've advanced tokenPtr just beyond the
     * subexpression's last token. For example, a "*" subexpression must







|






|







545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
		    if (code != TCL_OK) {
			goto done;
		    }
		    tokenPtr = endPtr;
		    break;
		    
		default:
		    Tcl_Panic("CompileSubExpr: unexpected operator %d requiring special treatment\n",
		        opIndex);
	    } /* end switch on operator requiring special treatment */
	    infoPtr->hasOperators = 1;
	    break;

        default:
	    Tcl_Panic("CompileSubExpr: unexpected token type %d\n",
	            tokenPtr->type);
    }

    /*
     * Verify that the subexpression token had the required number of
     * subtokens: that we've advanced tokenPtr just beyond the
     * subexpression's last token. For example, a "*" subexpression must
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
    CompileEnv *envPtr;		 /* Holds resulting instructions. */
    Tcl_Token **endPtrPtr;	 /* If successful, a pointer to the token
				  * just after the last token in the
				  * subexpression is stored here. */
{
    JumpFixup shortCircuitFixup; /* Used to fix up the short circuit jump
				  * after the first subexpression. */
    JumpFixup lhsTrueFixup, lhsEndFixup;

    				 /* Used to fix up jumps used to convert the
				  * first operand to 0 or 1. */
    Tcl_Token *tokenPtr;
    int dist, code;
    int savedStackDepth = envPtr->currStackDepth;

    /*
     * Emit code for the first operand.
     */

    tokenPtr = exprTokenPtr+2;
    code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
    if (code != TCL_OK) {
	goto done;
    }
    tokenPtr += (tokenPtr->numComponents + 1);

    /*
     * Convert the first operand to the result that Tcl requires:
     * "0" or "1". Eventually we'll use a new instruction for this.
     */
    
    TclEmitForwardJump(envPtr, TCL_TRUE_JUMP, &lhsTrueFixup);
    TclEmitPush(TclRegisterNewLiteral(envPtr, "0", 1), envPtr);
    TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &lhsEndFixup);
    dist = (envPtr->codeNext - envPtr->codeStart) - lhsTrueFixup.codeOffset;
    if (TclFixupForwardJump(envPtr, &lhsTrueFixup, dist, 127)) {
        badDist:
	panic("CompileLandOrLorExpr: bad jump distance %d\n", dist);
    }
    envPtr->currStackDepth = savedStackDepth;
    TclEmitPush(TclRegisterNewLiteral(envPtr, "1", 1), envPtr);
    dist = (envPtr->codeNext - envPtr->codeStart) - lhsEndFixup.codeOffset;
    if (TclFixupForwardJump(envPtr, &lhsEndFixup, dist, 127)) {
	goto badDist;
    }

    /*
     * Emit the "short circuit" jump around the rest of the expression.
     * Duplicate the "0" or "1" on top of the stack first to keep the
     * jump from consuming it.
     */

    TclEmitOpcode(INST_DUP, envPtr);
    TclEmitForwardJump(envPtr,
	    ((opIndex==OP_LAND)? TCL_FALSE_JUMP : TCL_TRUE_JUMP),
	    &shortCircuitFixup);

    /*
     * Emit code for the second operand.
     */

    code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
    if (code != TCL_OK) {
	goto done;
    }
    tokenPtr += (tokenPtr->numComponents + 1);

    /*
     * Emit a "logical and" or "logical or" instruction. This does not try
     * to "short- circuit" the evaluation of both operands, but instead

     * ensures that we either have a "1" or a "0" result.
     */


    TclEmitOpcode(((opIndex==OP_LAND)? INST_LAND : INST_LOR), envPtr);









    /*



     * Now that we know the target of the forward jump, update it with the
     * correct distance.




     */



    dist = (envPtr->codeNext - envPtr->codeStart)





	    - shortCircuitFixup.codeOffset;
    TclFixupForwardJump(envPtr, &shortCircuitFixup, dist, 127);
    *endPtrPtr = tokenPtr;

    done:
    envPtr->currStackDepth = savedStackDepth + 1;
    return code;
}








|
>
|
<

|














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


<













|

<
|
>
|


>
|
>

>
>
>
>
>
>
>

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







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
    CompileEnv *envPtr;		 /* Holds resulting instructions. */
    Tcl_Token **endPtrPtr;	 /* If successful, a pointer to the token
				  * just after the last token in the
				  * subexpression is stored here. */
{
    JumpFixup shortCircuitFixup; /* Used to fix up the short circuit jump
				  * after the first subexpression. */
    JumpFixup shortCircuitFixup2;/* Used to fix up the second jump to the
				  * short-circuit target. */
    JumpFixup endFixup;          /* Used to fix up jump to the end. */

    Tcl_Token *tokenPtr;
    int code;
    int savedStackDepth = envPtr->currStackDepth;

    /*
     * Emit code for the first operand.
     */

    tokenPtr = exprTokenPtr+2;
    code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
    if (code != TCL_OK) {
	goto done;
    }
    tokenPtr += (tokenPtr->numComponents + 1);

    /*



     * Emit the short-circuit jump.



















     */


    TclEmitForwardJump(envPtr,
	    ((opIndex==OP_LAND)? TCL_FALSE_JUMP : TCL_TRUE_JUMP),
	    &shortCircuitFixup);

    /*
     * Emit code for the second operand.
     */

    code = CompileSubExpr(tokenPtr, infoPtr, envPtr);
    if (code != TCL_OK) {
	goto done;
    }
    tokenPtr += (tokenPtr->numComponents + 1);
	    
    /*

     * The result is the boolean value of the second operand. We 
     * code this in a somewhat contorted manner to be able to reuse
     * the shortCircuit value and save one INST_JUMP.
     */

    TclEmitForwardJump(envPtr,
	    ((opIndex==OP_LAND)? TCL_FALSE_JUMP : TCL_TRUE_JUMP),
	    &shortCircuitFixup2);

    if (opIndex == OP_LAND) {
	TclEmitPush(TclRegisterNewLiteral(envPtr, "1", 1), envPtr);
    } else {
	TclEmitPush(TclRegisterNewLiteral(envPtr, "0", 1), envPtr);
    }
    TclEmitForwardJump(envPtr, TCL_UNCONDITIONAL_JUMP, &endFixup);

    /*
     * Fixup the short-circuit jumps and push the shortCircuit value.
     * Note that shortCircuitFixup2 is always a short jump.
     */


    TclFixupForwardJumpToHere(envPtr, &shortCircuitFixup2, 127);
    if (TclFixupForwardJumpToHere(envPtr, &shortCircuitFixup, 127)) {
	/*
	 * shortCircuit jump grown by 3 bytes: update endFixup.
	 */
	    
	 endFixup.codeOffset += 3;
    }

    if (opIndex == OP_LAND) {
	TclEmitPush(TclRegisterNewLiteral(envPtr, "0", 1), envPtr);
    } else {
	TclEmitPush(TclRegisterNewLiteral(envPtr, "1", 1), envPtr);
    }

    TclFixupForwardJumpToHere(envPtr, &endFixup, 127);
    *endPtrPtr = tokenPtr;

    done:
    envPtr->currStackDepth = savedStackDepth + 1;
    return code;
}

Changes to generic/tclCompile.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclCompile.c --
 *
 *	This file contains procedures that compile Tcl commands or parts
 *	of commands (like quoted strings or nested sub-commands) into a
 *	sequence of instructions ("bytecodes"). 
 *
 * Copyright (c) 1996-1998 Sun Microsystems, Inc.
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclCompile.c,v 1.49.2.2 2003/10/16 02:28:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"

/*
 * Table of all AuxData types.













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclCompile.c --
 *
 *	This file contains procedures that compile Tcl commands or parts
 *	of commands (like quoted strings or nested sub-commands) into a
 *	sequence of instructions ("bytecodes"). 
 *
 * Copyright (c) 1996-1998 Sun Microsystems, Inc.
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclCompile.c,v 1.49.2.3 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"

/*
 * Table of all AuxData types.
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
 * Note that the load, store, and incr instructions do not distinguish local
 * from global variables; the bytecode interpreter at runtime uses the
 * existence of a procedure call frame to distinguish these.
 */

InstructionDesc tclInstructionTable[] = {
   /* Name	      Bytes stackEffect #Opnds Operand types	Stack top, next	  */
    {"done",		  1,   -1,        0,   {OPERAND_NONE}},
	/* Finish ByteCode execution and return stktop (top stack item) */
    {"push1",		  2,   +1,         1,   {OPERAND_UINT1}},
	/* Push object at ByteCode objArray[op1] */
    {"push4",		  5,   +1,         1,   {OPERAND_UINT4}},
	/* Push object at ByteCode objArray[op4] */
    {"pop",		  1,   -1,        0,   {OPERAND_NONE}},
	/* Pop the topmost stack object */
    {"dup",		  1,   +1,         0,   {OPERAND_NONE}},
	/* Duplicate the topmost stack object and push the result */
    {"concat1",		  2,   INT_MIN,    1,   {OPERAND_UINT1}},
	/* Concatenate the top op1 items and push result */
    {"invokeStk1",	  2,   INT_MIN,    1,   {OPERAND_UINT1}},
	/* Invoke command named objv[0]; <objc,objv> = <op1,top op1> */







|





|







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
 * Note that the load, store, and incr instructions do not distinguish local
 * from global variables; the bytecode interpreter at runtime uses the
 * existence of a procedure call frame to distinguish these.
 */

InstructionDesc tclInstructionTable[] = {
   /* Name	      Bytes stackEffect #Opnds Operand types	Stack top, next	  */
    {"done",		  1,   -1,         0,   {OPERAND_NONE}},
	/* Finish ByteCode execution and return stktop (top stack item) */
    {"push1",		  2,   +1,         1,   {OPERAND_UINT1}},
	/* Push object at ByteCode objArray[op1] */
    {"push4",		  5,   +1,         1,   {OPERAND_UINT4}},
	/* Push object at ByteCode objArray[op4] */
    {"pop",		  1,   -1,         0,   {OPERAND_NONE}},
	/* Pop the topmost stack object */
    {"dup",		  1,   +1,         0,   {OPERAND_NONE}},
	/* Duplicate the topmost stack object and push the result */
    {"concat1",		  2,   INT_MIN,    1,   {OPERAND_UINT1}},
	/* Concatenate the top op1 items and push result */
    {"invokeStk1",	  2,   INT_MIN,    1,   {OPERAND_UINT1}},
	/* Invoke command named objv[0]; <objc,objv> = <op1,top op1> */
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
	/* Store scalar variable at op1<=255 in frame; value is stktop */
    {"storeScalar4",	  5,   0,          1,   {OPERAND_UINT4}},
	/* Store scalar variable at op1 > 255 in frame; value is stktop */
    {"storeScalarStk",	  1,   -1,         0,   {OPERAND_NONE}},
	/* Store scalar; value is stktop, scalar name is stknext */
    {"storeArray1",	  2,   -1,         1,   {OPERAND_UINT1}},
	/* Store array element; array at op1<=255, value is top then elem */
    {"storeArray4",	  5,   -1,          1,   {OPERAND_UINT4}},
	/* Store array element; array at op1>=256, value is top then elem */
    {"storeArrayStk",	  1,   -2,         0,   {OPERAND_NONE}},
	/* Store array element; value is stktop, then elem, array names */
    {"storeStk",	  1,   -1,         0,   {OPERAND_NONE}},
	/* Store general variable; value is stktop, then unparsed name */
    
    {"incrScalar1",	  2,   0,          1,   {OPERAND_UINT1}},
	/* Incr scalar at index op1<=255 in frame; incr amount is stktop */
    {"incrScalarStk",	  1,   -1,         0,   {OPERAND_NONE}},
	/* Incr scalar; incr amount is stktop, scalar's name is stknext */
    {"incrArray1",	  2,   -1,         1,   {OPERAND_UINT1}},
	/* Incr array elem; arr at slot op1<=255, amount is top then elem */
    {"incrArrayStk",	  1,   -2,         0,   {OPERAND_NONE}},
	/* Incr array element; amount is top then elem then array names */
    {"incrStk",		  1,   -1,         0,   {OPERAND_NONE}},
	/* Incr general variable; amount is stktop then unparsed var name */
    {"incrScalar1Imm",	  3,   +1,         2,   {OPERAND_UINT1, OPERAND_INT1}},
	/* Incr scalar at slot op1 <= 255; amount is 2nd operand byte */
    {"incrScalarStkImm",  2,   0,          1,   {OPERAND_INT1}},
	/* Incr scalar; scalar name is stktop; incr amount is op1 */
    {"incrArray1Imm",	  3,   0,         2,   {OPERAND_UINT1, OPERAND_INT1}},
	/* Incr array elem; array at slot op1 <= 255, elem is stktop,
	 * amount is 2nd operand byte */
    {"incrArrayStkImm",	  2,   -1,         1,   {OPERAND_INT1}},
	/* Incr array element; elem is top then array name, amount is op1 */
    {"incrStkImm",	  2,   0,         1,   {OPERAND_INT1}},
	/* Incr general variable; unparsed name is top, amount is op1 */
    
    {"jump1",		  2,   0,          1,   {OPERAND_INT1}},
	/* Jump relative to (pc + op1) */
    {"jump4",		  5,   0,          1,   {OPERAND_INT4}},
	/* Jump relative to (pc + op4) */
    {"jumpTrue1",	  2,   -1,         1,   {OPERAND_INT1}},







|




















|




|







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
	/* Store scalar variable at op1<=255 in frame; value is stktop */
    {"storeScalar4",	  5,   0,          1,   {OPERAND_UINT4}},
	/* Store scalar variable at op1 > 255 in frame; value is stktop */
    {"storeScalarStk",	  1,   -1,         0,   {OPERAND_NONE}},
	/* Store scalar; value is stktop, scalar name is stknext */
    {"storeArray1",	  2,   -1,         1,   {OPERAND_UINT1}},
	/* Store array element; array at op1<=255, value is top then elem */
    {"storeArray4",	  5,   -1,         1,   {OPERAND_UINT4}},
	/* Store array element; array at op1>=256, value is top then elem */
    {"storeArrayStk",	  1,   -2,         0,   {OPERAND_NONE}},
	/* Store array element; value is stktop, then elem, array names */
    {"storeStk",	  1,   -1,         0,   {OPERAND_NONE}},
	/* Store general variable; value is stktop, then unparsed name */
    
    {"incrScalar1",	  2,   0,          1,   {OPERAND_UINT1}},
	/* Incr scalar at index op1<=255 in frame; incr amount is stktop */
    {"incrScalarStk",	  1,   -1,         0,   {OPERAND_NONE}},
	/* Incr scalar; incr amount is stktop, scalar's name is stknext */
    {"incrArray1",	  2,   -1,         1,   {OPERAND_UINT1}},
	/* Incr array elem; arr at slot op1<=255, amount is top then elem */
    {"incrArrayStk",	  1,   -2,         0,   {OPERAND_NONE}},
	/* Incr array element; amount is top then elem then array names */
    {"incrStk",		  1,   -1,         0,   {OPERAND_NONE}},
	/* Incr general variable; amount is stktop then unparsed var name */
    {"incrScalar1Imm",	  3,   +1,         2,   {OPERAND_UINT1, OPERAND_INT1}},
	/* Incr scalar at slot op1 <= 255; amount is 2nd operand byte */
    {"incrScalarStkImm",  2,   0,          1,   {OPERAND_INT1}},
	/* Incr scalar; scalar name is stktop; incr amount is op1 */
    {"incrArray1Imm",	  3,   0,          2,   {OPERAND_UINT1, OPERAND_INT1}},
	/* Incr array elem; array at slot op1 <= 255, elem is stktop,
	 * amount is 2nd operand byte */
    {"incrArrayStkImm",	  2,   -1,         1,   {OPERAND_INT1}},
	/* Incr array element; elem is top then array name, amount is op1 */
    {"incrStkImm",	  2,   0,	   1,   {OPERAND_INT1}},
	/* Incr general variable; unparsed name is top, amount is op1 */
    
    {"jump1",		  2,   0,          1,   {OPERAND_INT1}},
	/* Jump relative to (pc + op1) */
    {"jump4",		  5,   0,          1,   {OPERAND_INT4}},
	/* Jump relative to (pc + op4) */
    {"jumpTrue1",	  2,   -1,         1,   {OPERAND_INT1}},
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
	/* Str Length:	push (strlen stktop) */
    {"strindex",	  1,   -1,         0,   {OPERAND_NONE}},
	/* Str Index:	push (strindex stknext stktop) */
    {"strmatch",	  2,   -1,         1,   {OPERAND_INT1}},
	/* Str Match:	push (strmatch stknext stktop) opnd == nocase */
    {"list",		  5,   INT_MIN,    1,   {OPERAND_UINT4}},
	/* List:	push (stk1 stk2 ... stktop) */
    {"listindex",	  1,   -1,         0,   {OPERAND_NONE}},
	/* List Index:	push (listindex stknext stktop) */
    {"listlength",	  1,   0,          0,   {OPERAND_NONE}},
	/* List Len:	push (listlength stktop) */
    {"appendScalar1",	  2,   0,          1,   {OPERAND_UINT1}},
	/* Append scalar variable at op1<=255 in frame; value is stktop */
    {"appendScalar4",	  5,   0,          1,   {OPERAND_UINT4}},
	/* Append scalar variable at op1 > 255 in frame; value is stktop */
    {"appendArray1",	  2,   -1,         1,   {OPERAND_UINT1}},
	/* Append array element; array at op1<=255, value is top then elem */







|

|







223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
	/* Str Length:	push (strlen stktop) */
    {"strindex",	  1,   -1,         0,   {OPERAND_NONE}},
	/* Str Index:	push (strindex stknext stktop) */
    {"strmatch",	  2,   -1,         1,   {OPERAND_INT1}},
	/* Str Match:	push (strmatch stknext stktop) opnd == nocase */
    {"list",		  5,   INT_MIN,    1,   {OPERAND_UINT4}},
	/* List:	push (stk1 stk2 ... stktop) */
    {"listIndex",	  1,   -1,         0,   {OPERAND_NONE}},
	/* List Index:	push (listindex stknext stktop) */
    {"listLength",	  1,   0,          0,   {OPERAND_NONE}},
	/* List Len:	push (listlength stktop) */
    {"appendScalar1",	  2,   0,          1,   {OPERAND_UINT1}},
	/* Append scalar variable at op1<=255 in frame; value is stktop */
    {"appendScalar4",	  5,   0,          1,   {OPERAND_UINT4}},
	/* Append scalar variable at op1 > 255 in frame; value is stktop */
    {"appendArray1",	  2,   -1,         1,   {OPERAND_UINT1}},
	/* Append array element; array at op1<=255, value is top then elem */
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
	/* Lappend array element; array at op1<=255, value is top then elem */
    {"lappendArray4",	  5,   -1,         1,   {OPERAND_UINT4}},
	/* Lappend array element; array at op1>=256, value is top then elem */
    {"lappendArrayStk",	  1,   -2,         0,   {OPERAND_NONE}},
	/* Lappend array element; value is stktop, then elem, array names */
    {"lappendStk",	  1,   -1,         0,   {OPERAND_NONE}},
	/* Lappend general variable; value is stktop, then unparsed name */
    {"lindexMulti",	  5,   INT_MIN,   1,   {OPERAND_UINT4}},
        /* Lindex with generalized args, operand is number of stacked objs 
	 * used: (operand-1) entries from stktop are the indices; then list 
	 * to process. */
    {"over",		  5,   +1,         1,   {OPERAND_UINT4}},
        /* Duplicate the arg-th element from top of stack (TOS=0) */
    {"lsetList",          1,   -2,         0,   {OPERAND_NONE}},
        /* Four-arg version of 'lset'. stktop is old value; next is
         * new element value, next is the index list; pushes new value */
    {"lsetFlat",          5,   INT_MIN,   1,   {OPERAND_UINT4}},
        /* Three- or >=5-arg version of 'lset', operand is number of 
	 * stacked objs: stktop is old value, next is new element value, next 
	 * come (operand-2) indices; pushes the new value.
	 */
    {"return",		  1,   -1,          0,   {OPERAND_NONE}},

	/* return TCL_RETURN code. */
    {"expon",		  1,   -1,	    0,	 {OPERAND_NONE}},
	/* Binary exponentiation operator: push (stknext ** stktop) */








    {0}
};

/*
 * Prototypes for procedures defined later in this file:
 */








|








|




|
>
|
|

>
>
>
>
>
>
>
>







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
	/* Lappend array element; array at op1<=255, value is top then elem */
    {"lappendArray4",	  5,   -1,         1,   {OPERAND_UINT4}},
	/* Lappend array element; array at op1>=256, value is top then elem */
    {"lappendArrayStk",	  1,   -2,         0,   {OPERAND_NONE}},
	/* Lappend array element; value is stktop, then elem, array names */
    {"lappendStk",	  1,   -1,         0,   {OPERAND_NONE}},
	/* Lappend general variable; value is stktop, then unparsed name */
    {"lindexMulti",	  5,   INT_MIN,    1,   {OPERAND_UINT4}},
        /* Lindex with generalized args, operand is number of stacked objs 
	 * used: (operand-1) entries from stktop are the indices; then list 
	 * to process. */
    {"over",		  5,   +1,         1,   {OPERAND_UINT4}},
        /* Duplicate the arg-th element from top of stack (TOS=0) */
    {"lsetList",          1,   -2,         0,   {OPERAND_NONE}},
        /* Four-arg version of 'lset'. stktop is old value; next is
         * new element value, next is the index list; pushes new value */
    {"lsetFlat",          5,   INT_MIN,    1,   {OPERAND_UINT4}},
        /* Three- or >=5-arg version of 'lset', operand is number of 
	 * stacked objs: stktop is old value, next is new element value, next 
	 * come (operand-2) indices; pushes the new value.
	 */
    {"return",		  9,   -2,         2,   {OPERAND_INT4, OPERAND_UINT4}},
	/* Compiled [return], code, level are operands; options and result
	 * are on the stack. */
    {"expon",		  1,   -1,	   0,	{OPERAND_NONE}},
	/* Binary exponentiation operator: push (stknext ** stktop) */
    {"listverify",	  1,    0,	   0,   {OPERAND_NONE}},
	/* Test that top of stack is a valid list; error if not */
    {"invokeExp",   INT_MIN,   INT_MIN,    2, {OPERAND_UINT4, OPERAND_ULIST1}},
	/* Invoke with expansion: <objc,objv> = expanded <op1,top op1> */
    {"listIndexImm",	  5,	0,	   1,	{OPERAND_IDX4}},
	/* List Index:	push (lindex stktop op4) */
    {"listRangeImm",	  9,	0,	   2,	{OPERAND_IDX4, OPERAND_IDX4}},
	/* List Range:	push (lrange stktop op4 op4) */
    {0}
};

/*
 * Prototypes for procedures defined later in this file:
 */

361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
    int length, result;
    char *string;

#ifdef TCL_COMPILE_DEBUG
    if (!traceInitialized) {
        if (Tcl_LinkVar(interp, "tcl_traceCompile",
	            (char *) &tclTraceCompile,  TCL_LINK_INT) != TCL_OK) {
            panic("SetByteCodeFromAny: unable to create link for tcl_traceCompile variable");
        }
        traceInitialized = 1;
    }
#endif

    string = Tcl_GetStringFromObj(objPtr, &length);
    TclInitCompileEnv(interp, &compEnv, string, length);







|







370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
    int length, result;
    char *string;

#ifdef TCL_COMPILE_DEBUG
    if (!traceInitialized) {
        if (Tcl_LinkVar(interp, "tcl_traceCompile",
	            (char *) &tclTraceCompile,  TCL_LINK_INT) != TCL_OK) {
            Tcl_Panic("SetByteCodeFromAny: unable to create link for tcl_traceCompile variable");
        }
        traceInitialized = 1;
    }
#endif

    string = Tcl_GetStringFromObj(objPtr, &length);
    TclInitCompileEnv(interp, &compEnv, string, length);
766
767
768
769
770
771
772















































































773
774
775
776
777
778
779
    if (envPtr->mallocedCmdMap) {
	ckfree((char *) envPtr->cmdMapPtr);
    }
    if (envPtr->mallocedAuxDataArray) {
	ckfree((char *) envPtr->auxDataArrayPtr);
    }
}
















































































/*
 *----------------------------------------------------------------------
 *
 * TclCompileScript --
 *
 *	Compile a Tcl script in a string.







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







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
    if (envPtr->mallocedCmdMap) {
	ckfree((char *) envPtr->cmdMapPtr);
    }
    if (envPtr->mallocedAuxDataArray) {
	ckfree((char *) envPtr->auxDataArrayPtr);
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TclWordKnownAtCompileTime --
 *
 *	Test whether the value of a token is completely known at compile
 *	time.
 *
 * Results:
 *	Returns true if the tokenPtr argument points to a word value that
 *	is completely known at compile time.  Generally, values that are
 *	known at compile time can be compiled to their values, while values
 *	that cannot be	known until substitution at runtime must be compiled
 *	to bytecode instructions that perform that substitution.  For several
 *	commands, whether or not arguments are known at compile time determine
 *	whether it is worthwhile to compile at all.
 *
 * Side effects:
 *	When returning true, appends the known value of the word to
 *	the unshared Tcl_Obj (*valuePtr), unless valuePtr is NULL.
 *
 *----------------------------------------------------------------------
 */

int
TclWordKnownAtCompileTime(tokenPtr, valuePtr)
    Tcl_Token *tokenPtr;	/* Points to Tcl_Token we should check */
    Tcl_Obj *valuePtr;		/* If not NULL, points to an unshared Tcl_Obj
				 * to which we should append the known value
				 * of the word. */
{
    int numComponents = tokenPtr->numComponents;
    Tcl_Obj *tempPtr = NULL;

    if (tokenPtr->type == TCL_TOKEN_SIMPLE_WORD) {
	if (valuePtr != NULL) {
	    Tcl_AppendToObj(valuePtr, tokenPtr->start, tokenPtr->size);
	}
	return 1;
    }
    if (tokenPtr->type != TCL_TOKEN_WORD) {
	return 0;
    }
    tokenPtr++;
    if (valuePtr != NULL) {
	tempPtr = Tcl_NewObj();
	Tcl_IncrRefCount(tempPtr);
    }
    while (numComponents--) {
	switch (tokenPtr->type) {
	    case TCL_TOKEN_TEXT:
		if (tempPtr != NULL) {
		    Tcl_AppendToObj(tempPtr, tokenPtr->start, tokenPtr->size);
		}
		continue;

	    case TCL_TOKEN_BS:
		if (tempPtr != NULL) {
		    char utfBuf[TCL_UTF_MAX];
		    int length = 
			    Tcl_UtfBackslash(tokenPtr->start, NULL, utfBuf);
		    Tcl_AppendToObj(tempPtr, utfBuf, length);
		}
		continue;
	    
	    default:
		if (tempPtr != NULL) {
		    Tcl_DecrRefCount(tempPtr);
		}
		return 0;
	}
    }
    if (valuePtr != NULL) {
	Tcl_AppendObjToObj(valuePtr, tempPtr);
	Tcl_DecrRefCount(tempPtr);
    }
    return 1;
}

/*
 *----------------------------------------------------------------------
 *
 * TclCompileScript --
 *
 *	Compile a Tcl script in a string.
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
		}
		numObjsToConcat++;
		count -= tokenPtr->numComponents;
		tokenPtr += tokenPtr->numComponents;
		break;

	    default:
		panic("Unexpected token type in TclCompileTokens: %d; %.*s",
				tokenPtr->type, tokenPtr->size, tokenPtr->start);
	}
    }

    /*
     * Push any accumulated characters appearing at the end.
     */








|
|







1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
		}
		numObjsToConcat++;
		count -= tokenPtr->numComponents;
		tokenPtr += tokenPtr->numComponents;
		break;

	    default:
		Tcl_Panic("Unexpected token type in TclCompileTokens: %d; %.*s",
			tokenPtr->type, tokenPtr->size, tokenPtr->start);
	}
    }

    /*
     * Push any accumulated characters appearing at the end.
     */

1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
	codePtr->auxDataArrayPtr = NULL;
    }

    p += auxDataArrayBytes;
    nextPtr = EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
#ifdef TCL_COMPILE_DEBUG
    if (((size_t)(nextPtr - p)) != cmdLocBytes) {	
	panic("TclInitByteCodeObj: encoded cmd location bytes %d != expected size %d\n", (nextPtr - p), cmdLocBytes);
    }
#endif
    
    /*
     * Record various compilation-related statistics about the new ByteCode
     * structure. Don't include overhead for statistics-related fields.
     */







|







1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
	codePtr->auxDataArrayPtr = NULL;
    }

    p += auxDataArrayBytes;
    nextPtr = EncodeCmdLocMap(envPtr, codePtr, (unsigned char *) p);
#ifdef TCL_COMPILE_DEBUG
    if (((size_t)(nextPtr - p)) != cmdLocBytes) {	
	Tcl_Panic("TclInitByteCodeObj: encoded cmd location bytes %d != expected size %d\n", (nextPtr - p), cmdLocBytes);
    }
#endif
    
    /*
     * Record various compilation-related statistics about the new ByteCode
     * structure. Don't include overhead for statistics-related fields.
     */
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
				 * is being set. */
    int srcOffset;		/* Offset of first char of the command. */
    int codeOffset;		/* Offset of first byte of command code. */
{
    CmdLocation *cmdLocPtr;
    
    if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {
	panic("EnterCmdStartData: bad command index %d\n", cmdIndex);
    }
    
    if (cmdIndex >= envPtr->cmdMapEnd) {
	/*
	 * Expand the command location array by allocating more storage from
	 * the heap. The currently allocated CmdLocation entries are stored
	 * from cmdMapPtr[0] up to cmdMapPtr[envPtr->cmdMapEnd] (inclusive).







|







1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
				 * is being set. */
    int srcOffset;		/* Offset of first char of the command. */
    int codeOffset;		/* Offset of first byte of command code. */
{
    CmdLocation *cmdLocPtr;
    
    if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {
	Tcl_Panic("EnterCmdStartData: bad command index %d\n", cmdIndex);
    }
    
    if (cmdIndex >= envPtr->cmdMapEnd) {
	/*
	 * Expand the command location array by allocating more storage from
	 * the heap. The currently allocated CmdLocation entries are stored
	 * from cmdMapPtr[0] up to cmdMapPtr[envPtr->cmdMapEnd] (inclusive).
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
	envPtr->cmdMapPtr = (CmdLocation *) newPtr;
	envPtr->cmdMapEnd = newElems;
	envPtr->mallocedCmdMap = 1;
    }

    if (cmdIndex > 0) {
	if (codeOffset < envPtr->cmdMapPtr[cmdIndex-1].codeOffset) {
	    panic("EnterCmdStartData: cmd map not sorted by code offset");
	}
    }

    cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);
    cmdLocPtr->codeOffset = codeOffset;
    cmdLocPtr->srcOffset = srcOffset;
    cmdLocPtr->numSrcBytes = -1;







|







2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
	envPtr->cmdMapPtr = (CmdLocation *) newPtr;
	envPtr->cmdMapEnd = newElems;
	envPtr->mallocedCmdMap = 1;
    }

    if (cmdIndex > 0) {
	if (codeOffset < envPtr->cmdMapPtr[cmdIndex-1].codeOffset) {
	    Tcl_Panic("EnterCmdStartData: cmd map not sorted by code offset");
	}
    }

    cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);
    cmdLocPtr->codeOffset = codeOffset;
    cmdLocPtr->srcOffset = srcOffset;
    cmdLocPtr->numSrcBytes = -1;
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
				 * code length data is being set. */
    int numSrcBytes;		/* Number of command source chars. */
    int numCodeBytes;		/* Offset of last byte of command code. */
{
    CmdLocation *cmdLocPtr;

    if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {
	panic("EnterCmdExtentData: bad command index %d\n", cmdIndex);
    }
    
    if (cmdIndex > envPtr->cmdMapEnd) {
	panic("EnterCmdExtentData: missing start data for command %d\n",
	        cmdIndex);
    }

    cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);
    cmdLocPtr->numSrcBytes = numSrcBytes;
    cmdLocPtr->numCodeBytes = numCodeBytes;
}







|



|







2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
				 * code length data is being set. */
    int numSrcBytes;		/* Number of command source chars. */
    int numCodeBytes;		/* Offset of last byte of command code. */
{
    CmdLocation *cmdLocPtr;

    if ((cmdIndex < 0) || (cmdIndex >= envPtr->numCommands)) {
	Tcl_Panic("EnterCmdExtentData: bad command index %d\n", cmdIndex);
    }
    
    if (cmdIndex > envPtr->cmdMapEnd) {
	Tcl_Panic("EnterCmdExtentData: missing start data for command %d\n",
	        cmdIndex);
    }

    cmdLocPtr = &(envPtr->cmdMapPtr[cmdIndex]);
    cmdLocPtr->numSrcBytes = numSrcBytes;
    cmdLocPtr->numCodeBytes = numCodeBytes;
}
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
		rangePtr->continueOffset += 3;
	    }
	    break;
	case CATCH_EXCEPTION_RANGE:
	    rangePtr->catchOffset += 3;
	    break;
	default:
	    panic("TclFixupForwardJump: bad ExceptionRange type %d\n",
	            rangePtr->type);
	}
    }
    return 1;			/* the jump was grown */
}

/*







|







2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
		rangePtr->continueOffset += 3;
	    }
	    break;
	case CATCH_EXCEPTION_RANGE:
	    rangePtr->catchOffset += 3;
	    break;
	default:
	    Tcl_Panic("TclFixupForwardJump: bad ExceptionRange type %d\n",
	            rangePtr->type);
	}
    }
    return 1;			/* the jump was grown */
}

/*
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
    int prevCodeOffset, prevSrcOffset, i;

    codeDeltaNext = codeLengthNext = srcDeltaNext = srcLengthNext = 0;
    prevCodeOffset = prevSrcOffset = 0;
    for (i = 0;  i < numCmds;  i++) {
	codeDelta = (mapPtr[i].codeOffset - prevCodeOffset);
	if (codeDelta < 0) {
	    panic("GetCmdLocEncodingSize: bad code offset");
	} else if (codeDelta <= 127) {
	    codeDeltaNext++;
	} else {
	    codeDeltaNext += 5;	 /* 1 byte for 0xFF, 4 for positive delta */
	}
	prevCodeOffset = mapPtr[i].codeOffset;

	codeLen = mapPtr[i].numCodeBytes;
	if (codeLen < 0) {
	    panic("GetCmdLocEncodingSize: bad code length");
	} else if (codeLen <= 127) {
	    codeLengthNext++;
	} else {
	    codeLengthNext += 5; /* 1 byte for 0xFF, 4 for length */
	}

	srcDelta = (mapPtr[i].srcOffset - prevSrcOffset);
	if ((-127 <= srcDelta) && (srcDelta <= 127)) {
	    srcDeltaNext++;
	} else {
	    srcDeltaNext += 5;	 /* 1 byte for 0xFF, 4 for delta */
	}
	prevSrcOffset = mapPtr[i].srcOffset;

	srcLen = mapPtr[i].numSrcBytes;
	if (srcLen < 0) {
	    panic("GetCmdLocEncodingSize: bad source length");
	} else if (srcLen <= 127) {
	    srcLengthNext++;
	} else {
	    srcLengthNext += 5;	 /* 1 byte for 0xFF, 4 for length */
	}
    }








|









|
















|







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
    int prevCodeOffset, prevSrcOffset, i;

    codeDeltaNext = codeLengthNext = srcDeltaNext = srcLengthNext = 0;
    prevCodeOffset = prevSrcOffset = 0;
    for (i = 0;  i < numCmds;  i++) {
	codeDelta = (mapPtr[i].codeOffset - prevCodeOffset);
	if (codeDelta < 0) {
	    Tcl_Panic("GetCmdLocEncodingSize: bad code offset");
	} else if (codeDelta <= 127) {
	    codeDeltaNext++;
	} else {
	    codeDeltaNext += 5;	 /* 1 byte for 0xFF, 4 for positive delta */
	}
	prevCodeOffset = mapPtr[i].codeOffset;

	codeLen = mapPtr[i].numCodeBytes;
	if (codeLen < 0) {
	    Tcl_Panic("GetCmdLocEncodingSize: bad code length");
	} else if (codeLen <= 127) {
	    codeLengthNext++;
	} else {
	    codeLengthNext += 5; /* 1 byte for 0xFF, 4 for length */
	}

	srcDelta = (mapPtr[i].srcOffset - prevSrcOffset);
	if ((-127 <= srcDelta) && (srcDelta <= 127)) {
	    srcDeltaNext++;
	} else {
	    srcDeltaNext += 5;	 /* 1 byte for 0xFF, 4 for delta */
	}
	prevSrcOffset = mapPtr[i].srcOffset;

	srcLen = mapPtr[i].numSrcBytes;
	if (srcLen < 0) {
	    Tcl_Panic("GetCmdLocEncodingSize: bad source length");
	} else if (srcLen <= 127) {
	    srcLengthNext++;
	} else {
	    srcLengthNext += 5;	 /* 1 byte for 0xFF, 4 for length */
	}
    }

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
     */

    codePtr->codeDeltaStart = p;
    prevOffset = 0;
    for (i = 0;  i < numCmds;  i++) {
	codeDelta = (mapPtr[i].codeOffset - prevOffset);
	if (codeDelta < 0) {
	    panic("EncodeCmdLocMap: bad code offset");
	} else if (codeDelta <= 127) {
	    TclStoreInt1AtPtr(codeDelta, p);
	    p++;
	} else {
	    TclStoreInt1AtPtr(0xFF, p);
	    p++;
	    TclStoreInt4AtPtr(codeDelta, p);
	    p += 4;
	}
	prevOffset = mapPtr[i].codeOffset;
    }

    /*
     * Encode the code length for each command.
     */

    codePtr->codeLengthStart = p;
    for (i = 0;  i < numCmds;  i++) {
	codeLen = mapPtr[i].numCodeBytes;
	if (codeLen < 0) {
	    panic("EncodeCmdLocMap: bad code length");
	} else if (codeLen <= 127) {
	    TclStoreInt1AtPtr(codeLen, p);
	    p++;
	} else {
	    TclStoreInt1AtPtr(0xFF, p);
	    p++;
	    TclStoreInt4AtPtr(codeLen, p);







|




















|







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
     */

    codePtr->codeDeltaStart = p;
    prevOffset = 0;
    for (i = 0;  i < numCmds;  i++) {
	codeDelta = (mapPtr[i].codeOffset - prevOffset);
	if (codeDelta < 0) {
	    Tcl_Panic("EncodeCmdLocMap: bad code offset");
	} else if (codeDelta <= 127) {
	    TclStoreInt1AtPtr(codeDelta, p);
	    p++;
	} else {
	    TclStoreInt1AtPtr(0xFF, p);
	    p++;
	    TclStoreInt4AtPtr(codeDelta, p);
	    p += 4;
	}
	prevOffset = mapPtr[i].codeOffset;
    }

    /*
     * Encode the code length for each command.
     */

    codePtr->codeLengthStart = p;
    for (i = 0;  i < numCmds;  i++) {
	codeLen = mapPtr[i].numCodeBytes;
	if (codeLen < 0) {
	    Tcl_Panic("EncodeCmdLocMap: bad code length");
	} else if (codeLen <= 127) {
	    TclStoreInt1AtPtr(codeLen, p);
	    p++;
	} else {
	    TclStoreInt1AtPtr(0xFF, p);
	    p++;
	    TclStoreInt4AtPtr(codeLen, p);
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
     * Encode the source length for each command.
     */

    codePtr->srcLengthStart = p;
    for (i = 0;  i < numCmds;  i++) {
	srcLen = mapPtr[i].numSrcBytes;
	if (srcLen < 0) {
	    panic("EncodeCmdLocMap: bad source length");
	} else if (srcLen <= 127) {
	    TclStoreInt1AtPtr(srcLen, p);
	    p++;
	} else {
	    TclStoreInt1AtPtr(0xFF, p);
	    p++;
	    TclStoreInt4AtPtr(srcLen, p);







|







2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
     * Encode the source length for each command.
     */

    codePtr->srcLengthStart = p;
    for (i = 0;  i < numCmds;  i++) {
	srcLen = mapPtr[i].numSrcBytes;
	if (srcLen < 0) {
	    Tcl_Panic("EncodeCmdLocMap: bad source length");
	} else if (srcLen <= 127) {
	    TclStoreInt1AtPtr(srcLen, p);
	    p++;
	} else {
	    TclStoreInt1AtPtr(0xFF, p);
	    p++;
	    TclStoreInt4AtPtr(srcLen, p);
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
		fprintf(stdout,	"continue %d, break %d\n",
		        rangePtr->continueOffset, rangePtr->breakOffset);
		break;
	    case CATCH_EXCEPTION_RANGE:
		fprintf(stdout,	"catch %d\n", rangePtr->catchOffset);
		break;
	    default:
		panic("TclPrintByteCodeObj: bad ExceptionRange type %d\n",
		        rangePtr->type);
	    }
	}
    }
    
    /*
     * If there were no commands (e.g., an expression or an empty string







|







3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
		fprintf(stdout,	"continue %d, break %d\n",
		        rangePtr->continueOffset, rangePtr->breakOffset);
		break;
	    case CATCH_EXCEPTION_RANGE:
		fprintf(stdout,	"catch %d\n", rangePtr->catchOffset);
		break;
	    default:
		Tcl_Panic("TclPrintByteCodeObj: bad ExceptionRange type %d\n",
		        rangePtr->type);
	    }
	}
    }
    
    /*
     * If there were no commands (e.g., an expression or an empty string
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
    unsigned char *pc;		/* Points to first byte of instruction. */
{
    Proc *procPtr = codePtr->procPtr;
    unsigned char opCode = *pc;
    register InstructionDesc *instDesc = &tclInstructionTable[opCode];
    unsigned char *codeStart = codePtr->codeStart;
    unsigned int pcOffset = (pc - codeStart);
    int opnd, i, j;
    
    fprintf(stdout, "(%u) %s ", pcOffset, instDesc->name);
    for (i = 0;  i < instDesc->numOperands;  i++) {
	switch (instDesc->opTypes[i]) {
	case OPERAND_INT1:
	    opnd = TclGetInt1AtPtr(pc+1+i);
	    if ((i == 0) && ((opCode == INST_JUMP1)
			     || (opCode == INST_JUMP_TRUE1)
		             || (opCode == INST_JUMP_FALSE1))) {
		fprintf(stdout, "%d  	# pc %u", opnd, (pcOffset + opnd));
	    } else {
		fprintf(stdout, "%d", opnd);
	    }
	    break;
	case OPERAND_INT4:
	    opnd = TclGetInt4AtPtr(pc+1+i);
	    if ((i == 0) && ((opCode == INST_JUMP4)
			     || (opCode == INST_JUMP_TRUE4)
		             || (opCode == INST_JUMP_FALSE4))) {
		fprintf(stdout, "%d  	# pc %u", opnd, (pcOffset + opnd));
	    } else {
		fprintf(stdout, "%d", opnd);
	    }
	    break;
	case OPERAND_UINT1:
	    opnd = TclGetUInt1AtPtr(pc+1+i);
	    if ((i == 0) && (opCode == INST_PUSH1)) {
		fprintf(stdout, "%u  	# ", (unsigned int) opnd);
		TclPrintObject(stdout, codePtr->objArrayPtr[opnd], 40);
	    } else if ((i == 0) && ((opCode == INST_LOAD_SCALAR1)
				    || (opCode == INST_LOAD_ARRAY1)
				    || (opCode == INST_STORE_SCALAR1)
				    || (opCode == INST_STORE_ARRAY1))) {
		int localCt = procPtr->numCompiledLocals;
		CompiledLocal *localPtr = procPtr->firstLocalPtr;
		if (opnd >= localCt) {
		    panic("TclPrintInstruction: bad local var index %u (%u locals)\n",
			     (unsigned int) opnd, localCt);
		    return instDesc->numBytes;
		}
		for (j = 0;  j < opnd;  j++) {
		    localPtr = localPtr->nextPtr;
		}
		if (TclIsVarTemporary(localPtr)) {
		    fprintf(stdout, "%u	# temp var %u",
			    (unsigned int) opnd, (unsigned int) opnd);
		} else {
		    fprintf(stdout, "%u	# var ", (unsigned int) opnd);
		    TclPrintSource(stdout, localPtr->name, 40);
		}
	    } else {
		fprintf(stdout, "%u ", (unsigned int) opnd);
	    }
	    break;
	case OPERAND_UINT4:
	    opnd = TclGetUInt4AtPtr(pc+1+i);
	    if (opCode == INST_PUSH4) {
		fprintf(stdout, "%u  	# ", opnd);
		TclPrintObject(stdout, codePtr->objArrayPtr[opnd], 40);
	    } else if ((i == 0) && ((opCode == INST_LOAD_SCALAR4)
				    || (opCode == INST_LOAD_ARRAY4)
				    || (opCode == INST_STORE_SCALAR4)
				    || (opCode == INST_STORE_ARRAY4))) {
		int localCt = procPtr->numCompiledLocals;
		CompiledLocal *localPtr = procPtr->firstLocalPtr;
		if (opnd >= localCt) {
		    panic("TclPrintInstruction: bad local var index %u (%u locals)\n",
			     (unsigned int) opnd, localCt);
		    return instDesc->numBytes;
		}
		for (j = 0;  j < opnd;  j++) {
		    localPtr = localPtr->nextPtr;
		}
		if (TclIsVarTemporary(localPtr)) {
		    fprintf(stdout, "%u	# temp var %u",
			    (unsigned int) opnd, (unsigned int) opnd);
		} else {
		    fprintf(stdout, "%u	# var ", (unsigned int) opnd);
		    TclPrintSource(stdout, localPtr->name, 40);
		}
	    } else {
		fprintf(stdout, "%u ", (unsigned int) opnd);
	    }
	    break;






















	case OPERAND_NONE:
	default:
	    break;
	}
    }
    fprintf(stdout, "\n");
    return instDesc->numBytes;
}

/*
 *----------------------------------------------------------------------
 *
 * TclPrintObject --
 *







|





|









|









|










|

<
















|










|

<















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






|







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
    unsigned char *pc;		/* Points to first byte of instruction. */
{
    Proc *procPtr = codePtr->procPtr;
    unsigned char opCode = *pc;
    register InstructionDesc *instDesc = &tclInstructionTable[opCode];
    unsigned char *codeStart = codePtr->codeStart;
    unsigned int pcOffset = (pc - codeStart);
    int opnd, i, j, numBytes = 1;
    
    fprintf(stdout, "(%u) %s ", pcOffset, instDesc->name);
    for (i = 0;  i < instDesc->numOperands;  i++) {
	switch (instDesc->opTypes[i]) {
	case OPERAND_INT1:
	    opnd = TclGetInt1AtPtr(pc+numBytes); numBytes++;
	    if ((i == 0) && ((opCode == INST_JUMP1)
			     || (opCode == INST_JUMP_TRUE1)
		             || (opCode == INST_JUMP_FALSE1))) {
		fprintf(stdout, "%d  	# pc %u", opnd, (pcOffset + opnd));
	    } else {
		fprintf(stdout, "%d", opnd);
	    }
	    break;
	case OPERAND_INT4:
	    opnd = TclGetInt4AtPtr(pc+numBytes); numBytes += 4;
	    if ((i == 0) && ((opCode == INST_JUMP4)
			     || (opCode == INST_JUMP_TRUE4)
		             || (opCode == INST_JUMP_FALSE4))) {
		fprintf(stdout, "%d  	# pc %u", opnd, (pcOffset + opnd));
	    } else {
		fprintf(stdout, "%d", opnd);
	    }
	    break;
	case OPERAND_UINT1:
	    opnd = TclGetUInt1AtPtr(pc+numBytes); numBytes++;
	    if ((i == 0) && (opCode == INST_PUSH1)) {
		fprintf(stdout, "%u  	# ", (unsigned int) opnd);
		TclPrintObject(stdout, codePtr->objArrayPtr[opnd], 40);
	    } else if ((i == 0) && ((opCode == INST_LOAD_SCALAR1)
				    || (opCode == INST_LOAD_ARRAY1)
				    || (opCode == INST_STORE_SCALAR1)
				    || (opCode == INST_STORE_ARRAY1))) {
		int localCt = procPtr->numCompiledLocals;
		CompiledLocal *localPtr = procPtr->firstLocalPtr;
		if (opnd >= localCt) {
		    Tcl_Panic("TclPrintInstruction: bad local var index %u (%u locals)\n",
			     (unsigned int) opnd, localCt);

		}
		for (j = 0;  j < opnd;  j++) {
		    localPtr = localPtr->nextPtr;
		}
		if (TclIsVarTemporary(localPtr)) {
		    fprintf(stdout, "%u	# temp var %u",
			    (unsigned int) opnd, (unsigned int) opnd);
		} else {
		    fprintf(stdout, "%u	# var ", (unsigned int) opnd);
		    TclPrintSource(stdout, localPtr->name, 40);
		}
	    } else {
		fprintf(stdout, "%u ", (unsigned int) opnd);
	    }
	    break;
	case OPERAND_UINT4:
	    opnd = TclGetUInt4AtPtr(pc+numBytes); numBytes += 4;
	    if (opCode == INST_PUSH4) {
		fprintf(stdout, "%u  	# ", opnd);
		TclPrintObject(stdout, codePtr->objArrayPtr[opnd], 40);
	    } else if ((i == 0) && ((opCode == INST_LOAD_SCALAR4)
				    || (opCode == INST_LOAD_ARRAY4)
				    || (opCode == INST_STORE_SCALAR4)
				    || (opCode == INST_STORE_ARRAY4))) {
		int localCt = procPtr->numCompiledLocals;
		CompiledLocal *localPtr = procPtr->firstLocalPtr;
		if (opnd >= localCt) {
		    Tcl_Panic("TclPrintInstruction: bad local var index %u (%u locals)\n",
			     (unsigned int) opnd, localCt);

		}
		for (j = 0;  j < opnd;  j++) {
		    localPtr = localPtr->nextPtr;
		}
		if (TclIsVarTemporary(localPtr)) {
		    fprintf(stdout, "%u	# temp var %u",
			    (unsigned int) opnd, (unsigned int) opnd);
		} else {
		    fprintf(stdout, "%u	# var ", (unsigned int) opnd);
		    TclPrintSource(stdout, localPtr->name, 40);
		}
	    } else {
		fprintf(stdout, "%u ", (unsigned int) opnd);
	    }
	    break;

	case OPERAND_ULIST1:
	    opnd = TclGetUInt1AtPtr(pc+numBytes); numBytes++;
	    fprintf(stdout, "{");
	    while (opnd) {
		fprintf(stdout, "%u ", opnd);
	        opnd = TclGetUInt1AtPtr(pc+numBytes); numBytes++;
	    }
	    fprintf(stdout, "0}");
	    break;

	case OPERAND_IDX4:
	    opnd = TclGetInt4AtPtr(pc+numBytes); numBytes += 4;
	    if (opnd >= -1) {
		fprintf(stdout, "%d ", opnd);
	    } else if (opnd == -2) {
		fprintf(stdout, "end ");
	    } else {
		fprintf(stdout, "end-%d ", -2-opnd);
            }
	    break;

	case OPERAND_NONE:
	default:
	    break;
	}
    }
    fprintf(stdout, "\n");
    return numBytes;
}

/*
 *----------------------------------------------------------------------
 *
 * TclPrintObject --
 *
Changes to generic/tclCompile.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
 * tclCompile.h --
 *
 * Copyright (c) 1996-1998 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 by Scriptics Corporation.
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclCompile.h,v 1.36.2.2 2003/10/16 02:28:01 dgp Exp $
 */

#ifndef _TCLCOMPILATION
#define _TCLCOMPILATION 1

#ifndef _TCLINT
#include "tclInt.h"










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
 * tclCompile.h --
 *
 * Copyright (c) 1996-1998 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 by Scriptics Corporation.
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclCompile.h,v 1.36.2.3 2004/02/07 05:48:00 dgp Exp $
 */

#ifndef _TCLCOMPILATION
#define _TCLCOMPILATION 1

#ifndef _TCLINT
#include "tclInt.h"
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
 * We define a separate AuxDataType struct to hold type-related information
 * for the AuxData structure. This separation makes it possible for clients
 * outside of the TCL core to manipulate (in a limited fashion!) AuxData;
 * for example, it makes it possible to pickle and unpickle AuxData structs.
 */

typedef struct AuxDataType {
    char *name;					/* the name of the type. Types can be
                                 * registered and found by name */
    AuxDataDupProc *dupProc;	/* Callback procedure to invoke when the
                                 * aux data is duplicated (e.g., when the
                                 * ByteCode structure containing the aux
                                 * data is duplicated). NULL means just
                                 * copy the source clientData bits; no
                                 * proc need be called. */
    AuxDataFreeProc *freeProc;	/* Callback procedure to invoke when the
                                 * aux data is freed. NULL means no
                                 * proc need be called. */
} AuxDataType;

/*
 * The definition of the AuxData structure that holds information created
 * during compilation by CompileProcs and used by instructions during
 * execution.
 */

typedef struct AuxData {
    AuxDataType *type;		/* pointer to the AuxData type associated with
                             * this ClientData. */
    ClientData clientData;	/* The compilation data itself. */
} AuxData;

/*
 * Structure defining the compilation environment. After compilation, fields
 * describing bytecode instructions are copied out into the more compact
 * ByteCode structure defined below.







|
|

|
|
|
|
|

|
|










|







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
 * We define a separate AuxDataType struct to hold type-related information
 * for the AuxData structure. This separation makes it possible for clients
 * outside of the TCL core to manipulate (in a limited fashion!) AuxData;
 * for example, it makes it possible to pickle and unpickle AuxData structs.
 */

typedef struct AuxDataType {
    char *name;			/* the name of the type. Types can be
				 * registered and found by name */
    AuxDataDupProc *dupProc;	/* Callback procedure to invoke when the
				 * aux data is duplicated (e.g., when the
				 * ByteCode structure containing the aux
				 * data is duplicated). NULL means just
				 * copy the source clientData bits; no
				 * proc need be called. */
    AuxDataFreeProc *freeProc;	/* Callback procedure to invoke when the
				 * aux data is freed. NULL means no
				 * proc need be called. */
} AuxDataType;

/*
 * The definition of the AuxData structure that holds information created
 * during compilation by CompileProcs and used by instructions during
 * execution.
 */

typedef struct AuxData {
    AuxDataType *type;		/* pointer to the AuxData type associated with
				 * this ClientData. */
    ClientData clientData;	/* The compilation data itself. */
} AuxData;

/*
 * Structure defining the compilation environment. After compilation, fields
 * describing bytecode instructions are copied out into the more compact
 * ByteCode structure defined below.
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
    int exceptDepth;		/* Current exception range nesting level;
				 * -1 if not in any range currently. */
    int maxExceptDepth;		/* Max nesting level of exception ranges;
				 * -1 if no ranges have been compiled. */
    int maxStackDepth;		/* Maximum number of stack elements needed
				 * to execute the code. Set by compilation
				 * procedures before returning. */
    int currStackDepth;         /* Current stack depth. */
    LiteralTable localLitTable;	/* Contains LiteralEntry's describing
				 * all Tcl objects referenced by this
				 * compiled code. Indexed by the string
				 * representations of the literals. Used to
				 * avoid creating duplicate objects. */
    unsigned char *codeStart;	/* Points to the first byte of the code. */
    unsigned char *codeNext;	/* Points to next code array byte to use. */
    unsigned char *codeEnd;	/* Points just after the last allocated
				 * code array byte. */
    int mallocedCodeArray;      /* Set 1 if code array was expanded 
				 * and codeStart points into the heap.*/
    LiteralEntry *literalArrayPtr;
    				/* Points to start of LiteralEntry array. */
    int literalArrayNext;	/* Index of next free object array entry. */
    int literalArrayEnd;	/* Index just after last obj array entry. */
    int mallocedLiteralArray;   /* 1 if object array was expanded and
                                 * objArray points into the heap, else 0. */
    ExceptionRange *exceptArrayPtr;
    				/* Points to start of the ExceptionRange
				 * array. */
    int exceptArrayNext;	/* Next free ExceptionRange array index.
				 * exceptArrayNext is the number of ranges
				 * and (exceptArrayNext-1) is the index of
				 * the current range's array entry. */
    int exceptArrayEnd;		/* Index after the last ExceptionRange
				 * array entry. */
    int mallocedExceptArray;	/* 1 if ExceptionRange array was expanded
				 * and exceptArrayPtr points in heap,
				 * else 0. */
    CmdLocation *cmdMapPtr;	/* Points to start of CmdLocation array.
				 * numCommands is the index of the next
				 * entry to use; (numCommands-1) is the
				 * entry index for the last command. */
    int cmdMapEnd;		/* Index after last CmdLocation entry. */
    int mallocedCmdMap;		/* 1 if command map array was expanded and
				 * cmdMapPtr points in the heap, else 0. */
    AuxData *auxDataArrayPtr;   /* Points to auxiliary data array start. */
    int auxDataArrayNext;	/* Next free compile aux data array index.
				 * auxDataArrayNext is the number of aux
				 * data items and (auxDataArrayNext-1) is
				 * index of current aux data array entry. */
    int auxDataArrayEnd;	/* Index after last aux data array entry. */
    int mallocedAuxDataArray;	/* 1 if aux data array was expanded and
				 * auxDataArrayPtr points in heap else 0. */
    unsigned char staticCodeSpace[COMPILEENV_INIT_CODE_BYTES];
                                /* Initial storage for code. */
    LiteralEntry staticLiteralSpace[COMPILEENV_INIT_NUM_OBJECTS];
                                /* Initial storage of LiteralEntry array. */
    ExceptionRange staticExceptArraySpace[COMPILEENV_INIT_EXCEPT_RANGES];
                                /* Initial ExceptionRange array storage. */
    CmdLocation staticCmdMapSpace[COMPILEENV_INIT_CMD_MAP_SIZE];
                                /* Initial storage for cmd location map. */
    AuxData staticAuxDataArraySpace[COMPILEENV_INIT_AUX_DATA_SIZE];
                                /* Initial storage for aux data array. */
} CompileEnv;

/*
 * The structure defining the bytecode instructions resulting from compiling
 * a Tcl script. Note that this structure is variable length: a single heap
 * object is allocated to hold the ByteCode structure immediately followed
 * by the code bytes, the literal object array, the ExceptionRange array,







|









|





|
|



















|








|

|

|

|

|







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
    int exceptDepth;		/* Current exception range nesting level;
				 * -1 if not in any range currently. */
    int maxExceptDepth;		/* Max nesting level of exception ranges;
				 * -1 if no ranges have been compiled. */
    int maxStackDepth;		/* Maximum number of stack elements needed
				 * to execute the code. Set by compilation
				 * procedures before returning. */
    int currStackDepth;		/* Current stack depth. */
    LiteralTable localLitTable;	/* Contains LiteralEntry's describing
				 * all Tcl objects referenced by this
				 * compiled code. Indexed by the string
				 * representations of the literals. Used to
				 * avoid creating duplicate objects. */
    unsigned char *codeStart;	/* Points to the first byte of the code. */
    unsigned char *codeNext;	/* Points to next code array byte to use. */
    unsigned char *codeEnd;	/* Points just after the last allocated
				 * code array byte. */
    int mallocedCodeArray;	/* Set 1 if code array was expanded 
				 * and codeStart points into the heap.*/
    LiteralEntry *literalArrayPtr;
    				/* Points to start of LiteralEntry array. */
    int literalArrayNext;	/* Index of next free object array entry. */
    int literalArrayEnd;	/* Index just after last obj array entry. */
    int mallocedLiteralArray;	/* 1 if object array was expanded and
				 * objArray points into the heap, else 0. */
    ExceptionRange *exceptArrayPtr;
    				/* Points to start of the ExceptionRange
				 * array. */
    int exceptArrayNext;	/* Next free ExceptionRange array index.
				 * exceptArrayNext is the number of ranges
				 * and (exceptArrayNext-1) is the index of
				 * the current range's array entry. */
    int exceptArrayEnd;		/* Index after the last ExceptionRange
				 * array entry. */
    int mallocedExceptArray;	/* 1 if ExceptionRange array was expanded
				 * and exceptArrayPtr points in heap,
				 * else 0. */
    CmdLocation *cmdMapPtr;	/* Points to start of CmdLocation array.
				 * numCommands is the index of the next
				 * entry to use; (numCommands-1) is the
				 * entry index for the last command. */
    int cmdMapEnd;		/* Index after last CmdLocation entry. */
    int mallocedCmdMap;		/* 1 if command map array was expanded and
				 * cmdMapPtr points in the heap, else 0. */
    AuxData *auxDataArrayPtr;	/* Points to auxiliary data array start. */
    int auxDataArrayNext;	/* Next free compile aux data array index.
				 * auxDataArrayNext is the number of aux
				 * data items and (auxDataArrayNext-1) is
				 * index of current aux data array entry. */
    int auxDataArrayEnd;	/* Index after last aux data array entry. */
    int mallocedAuxDataArray;	/* 1 if aux data array was expanded and
				 * auxDataArrayPtr points in heap else 0. */
    unsigned char staticCodeSpace[COMPILEENV_INIT_CODE_BYTES];
				/* Initial storage for code. */
    LiteralEntry staticLiteralSpace[COMPILEENV_INIT_NUM_OBJECTS];
				/* Initial storage of LiteralEntry array. */
    ExceptionRange staticExceptArraySpace[COMPILEENV_INIT_EXCEPT_RANGES];
				/* Initial ExceptionRange array storage. */
    CmdLocation staticCmdMapSpace[COMPILEENV_INIT_CMD_MAP_SIZE];
				/* Initial storage for cmd location map. */
    AuxData staticAuxDataArraySpace[COMPILEENV_INIT_AUX_DATA_SIZE];
				/* Initial storage for aux data array. */
} CompileEnv;

/*
 * The structure defining the bytecode instructions resulting from compiling
 * a Tcl script. Note that this structure is variable length: a single heap
 * object is allocated to hold the ByteCode structure immediately followed
 * by the code bytes, the literal object array, the ExceptionRange array,
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
				 * code when new namespace resolution rules
				 * are put into effect. */
    int refCount;		/* Reference count: set 1 when created
				 * plus 1 for each execution of the code
				 * currently active. This structure can be
				 * freed when refCount becomes zero. */
    unsigned int flags;		/* flags describing state for the codebyte.
                                 * this variable holds ORed values from the
                                 * TCL_BYTECODE_ masks defined above */
    char *source;		/* The source string from which this
				 * ByteCode was compiled. Note that this
				 * pointer is not owned by the ByteCode and
				 * must not be freed or modified by it. */
    Proc *procPtr;		/* If the ByteCode was compiled from a
				 * procedure body, this is a pointer to its
				 * Proc structure; otherwise NULL. This







|
|







299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
				 * code when new namespace resolution rules
				 * are put into effect. */
    int refCount;		/* Reference count: set 1 when created
				 * plus 1 for each execution of the code
				 * currently active. This structure can be
				 * freed when refCount becomes zero. */
    unsigned int flags;		/* flags describing state for the codebyte.
				 * this variable holds ORed values from the
				 * TCL_BYTECODE_ masks defined above */
    char *source;		/* The source string from which this
				 * ByteCode was compiled. Note that this
				 * pointer is not owned by the ByteCode and
				 * must not be freed or modified by it. */
    Proc *procPtr;		/* If the ByteCode was compiled from a
				 * procedure body, this is a pointer to its
				 * Proc structure; otherwise NULL. This
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
    Tcl_Obj **objArrayPtr;	/* Points to the start of the literal
				 * object array. This is just after the
				 * last code byte. */
    ExceptionRange *exceptArrayPtr;
    				/* Points to the start of the ExceptionRange
				 * array. This is just after the last
				 * object in the object array. */
    AuxData *auxDataArrayPtr;   /* Points to the start of the auxiliary data
				 * array. This is just after the last entry
				 * in the ExceptionRange array. */
    unsigned char *codeDeltaStart;
				/* Points to the first of a sequence of
				 * bytes that encode the change in the
				 * starting offset of each command's code.
				 * If -127<=delta<=127, it is encoded as 1







|







336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
    Tcl_Obj **objArrayPtr;	/* Points to the start of the literal
				 * object array. This is just after the
				 * last code byte. */
    ExceptionRange *exceptArrayPtr;
    				/* Points to the start of the ExceptionRange
				 * array. This is just after the last
				 * object in the object array. */
    AuxData *auxDataArrayPtr;	/* Points to the start of the auxiliary data
				 * array. This is just after the last entry
				 * in the ExceptionRange array. */
    unsigned char *codeDeltaStart;
				/* Points to the first of a sequence of
				 * bytes that encode the change in the
				 * starting offset of each command's code.
				 * If -127<=delta<=127, it is encoded as 1
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447

/* Opcodes 34 to 39 */
#define INST_JUMP1			34
#define INST_JUMP4			35
#define INST_JUMP_TRUE1			36
#define INST_JUMP_TRUE4			37
#define INST_JUMP_FALSE1		38
#define INST_JUMP_FALSE4	        39

/* Opcodes 40 to 64 */
#define INST_LOR			40
#define INST_LAND			41
#define INST_BITOR			42
#define INST_BITXOR			43
#define INST_BITAND			44







|







433
434
435
436
437
438
439
440
441
442
443
444
445
446
447

/* Opcodes 34 to 39 */
#define INST_JUMP1			34
#define INST_JUMP4			35
#define INST_JUMP_TRUE1			36
#define INST_JUMP_TRUE4			37
#define INST_JUMP_FALSE1		38
#define INST_JUMP_FALSE4		39

/* Opcodes 40 to 64 */
#define INST_LOR			40
#define INST_LAND			41
#define INST_BITOR			42
#define INST_BITXOR			43
#define INST_BITAND			44
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

/* TIP #22 - LINDEX operator with flat arg list */

#define INST_LIST_INDEX_MULTI		94

/*
 * TIP #33 - 'lset' command.  Code gen also required a Forth-like
 *           OVER operation.
 */

#define INST_OVER                       95
#define INST_LSET_LIST			96
#define INST_LSET_FLAT                  97



#define INST_RETURN			98



#define INST_EXPON			99 /* TIP#123 - exponentiation */














/* The last opcode */
#define LAST_INST_OPCODE        	99

/*
 * 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" instruction.
 */

#define MAX_INSTRUCTION_OPERANDS 2

typedef enum InstOperandType {
    OPERAND_NONE,
    OPERAND_INT1,		/* One byte signed integer. */
    OPERAND_INT4,		/* Four byte signed integer. */
    OPERAND_UINT1,		/* One byte unsigned integer. */
    OPERAND_UINT4		/* Four byte unsigned integer. */



} InstOperandType;

typedef struct InstructionDesc {
    char *name;			/* Name of instruction. */
    int numBytes;		/* Total number of bytes for instruction. */
    int stackEffect;            /* The worst-case balance stack effect of the 
				 * instruction, used for stack requirements 
				 * computations. The value INT_MIN signals
				 * that the instruction's worst case effect
				 * is (1-opnd1).
				 */
    int numOperands;		/* Number of operands. */
    InstOperandType opTypes[MAX_INSTRUCTION_OPERANDS];







|


|

|
>
>



>
>
|

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

|

















|
>
>
>





|







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

/* TIP #22 - LINDEX operator with flat arg list */

#define INST_LIST_INDEX_MULTI		94

/*
 * TIP #33 - 'lset' command.  Code gen also required a Forth-like
 *	     OVER operation.
 */

#define INST_OVER			95
#define INST_LSET_LIST			96
#define INST_LSET_FLAT			97

/* TIP#90 - 'return' command. */

#define INST_RETURN			98

/* TIP#123 - exponentiation operator. */

#define INST_EXPON			99

/* TIP #157 - {expand}... language syntax support. */

#define INST_LIST_VERIFY		100
#define INST_INVOKE_EXP			101

/*
 * TIP #57 - 'lassign' command.  Code generation requires immediate
 *	     LINDEX and LRANGE operators.
 */

#define INST_LIST_INDEX_IMM		102
#define INST_LIST_RANGE_IMM		103

/* The last opcode */
#define LAST_INST_OPCODE		103

/*
 * 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" instruction.
 */

#define MAX_INSTRUCTION_OPERANDS 2

typedef enum InstOperandType {
    OPERAND_NONE,
    OPERAND_INT1,		/* One byte signed integer. */
    OPERAND_INT4,		/* Four byte signed integer. */
    OPERAND_UINT1,		/* One byte unsigned integer. */
    OPERAND_UINT4,		/* Four byte unsigned integer. */
    OPERAND_ULIST1,		/* List of one byte unsigned integers. */
    OPERAND_IDX4		/* Four byte signed index (actually an
				 * integer, but displayed differently.) */
} InstOperandType;

typedef struct InstructionDesc {
    char *name;			/* Name of instruction. */
    int numBytes;		/* Total number of bytes for instruction. */
    int stackEffect;		/* The worst-case balance stack effect of the 
				 * instruction, used for stack requirements 
				 * computations. The value INT_MIN signals
				 * that the instruction's worst case effect
				 * is (1-opnd1).
				 */
    int numOperands;		/* Number of operands. */
    InstOperandType opTypes[MAX_INSTRUCTION_OPERANDS];
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
#define BUILTIN_FUNC_DOUBLE		20
#define BUILTIN_FUNC_INT		21
#define BUILTIN_FUNC_RAND		22
#define BUILTIN_FUNC_ROUND		23
#define BUILTIN_FUNC_SRAND		24
#define BUILTIN_FUNC_WIDE		25

#define LAST_BUILTIN_FUNC        	25

/*
 * Table describing the built-in math functions. Entries in this table are
 * indexed by the values of the INST_CALL_BUILTIN_FUNC instruction's
 * operand byte.
 */

typedef int (CallBuiltinFuncProc) _ANSI_ARGS_((Tcl_Interp *interp,
        ExecEnv *eePtr, ClientData clientData));

typedef struct {
    char *name;			/* Name of function. */
    int numArgs;		/* Number of arguments for function. */
    Tcl_ValueType argTypes[MAX_MATH_ARGS];
				/* Acceptable types for each argument. */
    CallBuiltinFuncProc *proc;	/* Procedure implementing this function. */







|








|







615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
#define BUILTIN_FUNC_DOUBLE		20
#define BUILTIN_FUNC_INT		21
#define BUILTIN_FUNC_RAND		22
#define BUILTIN_FUNC_ROUND		23
#define BUILTIN_FUNC_SRAND		24
#define BUILTIN_FUNC_WIDE		25

#define LAST_BUILTIN_FUNC		25

/*
 * Table describing the built-in math functions. Entries in this table are
 * indexed by the values of the INST_CALL_BUILTIN_FUNC instruction's
 * operand byte.
 */

typedef int (CallBuiltinFuncProc) _ANSI_ARGS_((Tcl_Interp *interp,
	ExecEnv *eePtr, ClientData clientData));

typedef struct {
    char *name;			/* Name of function. */
    int numArgs;		/* Number of arguments for function. */
    Tcl_ValueType argTypes[MAX_MATH_ARGS];
				/* Acceptable types for each argument. */
    CallBuiltinFuncProc *proc;	/* Procedure implementing this function. */
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
				 * ExceptionRange array after the current
				 * one. This field is used to adjust the
				 * code offsets in subsequent ExceptionRange
				 * records when a jump is grown from 2 bytes
				 * to 5 bytes. */
} JumpFixup;

#define JUMPFIXUP_INIT_ENTRIES    10

typedef struct JumpFixupArray {
    JumpFixup *fixup;		/* Points to start of jump fixup array. */
    int next;			/* Index of next free array entry. */
    int end;			/* Index of last usable entry in array. */
    int mallocedArray;		/* 1 if array was expanded and fixups points
				 * into the heap, else 0. */







|







674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
				 * ExceptionRange array after the current
				 * one. This field is used to adjust the
				 * code offsets in subsequent ExceptionRange
				 * records when a jump is grown from 2 bytes
				 * to 5 bytes. */
} JumpFixup;

#define JUMPFIXUP_INIT_ENTRIES	10

typedef struct JumpFixupArray {
    JumpFixup *fixup;		/* Points to start of jump fixup array. */
    int next;			/* Index of next free array entry. */
    int end;			/* Index of last usable entry in array. */
    int mallocedArray;		/* 1 if array was expanded and fixups points
				 * into the heap, else 0. */
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732

/*
 *----------------------------------------------------------------
 * Procedures exported by tclBasic.c to be used within the engine.
 *----------------------------------------------------------------
 */

EXTERN int		TclEvalObjvInternal _ANSI_ARGS_((Tcl_Interp *interp, int objc,
			    Tcl_Obj *CONST objv[], CONST char *command, int length,
			    int flags));
EXTERN int              TclInterpReady _ANSI_ARGS_((Tcl_Interp *interp));


/*
 *----------------------------------------------------------------
 * Procedures exported by the engine to be used by tclBasic.c
 *----------------------------------------------------------------
 */







|
|
|
|







735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752

/*
 *----------------------------------------------------------------
 * Procedures exported by tclBasic.c to be used within the engine.
 *----------------------------------------------------------------
 */

EXTERN int		TclEvalObjvInternal _ANSI_ARGS_((Tcl_Interp *interp,
			    int objc, Tcl_Obj *CONST objv[],
			    CONST char *command, int length, int flags));
EXTERN int		TclInterpReady _ANSI_ARGS_((Tcl_Interp *interp));


/*
 *----------------------------------------------------------------
 * Procedures exported by the engine to be used by tclBasic.c
 *----------------------------------------------------------------
 */
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
EXTERN int		TclCompileExpr _ANSI_ARGS_((Tcl_Interp *interp,
			    CONST char *script, int numBytes,
			    CompileEnv *envPtr));
EXTERN int		TclCompileExprWords _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Token *tokenPtr, int numWords,
			    CompileEnv *envPtr));
EXTERN int		TclCompileScript _ANSI_ARGS_((Tcl_Interp *interp,
			    CONST char *script, int numBytes, CompileEnv *envPtr));

EXTERN int		TclCompileScriptTokens _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Token *tokens, Tcl_Token *lastTokenPtr,
			    CompileEnv *envPtr));
EXTERN int		TclCompileTokens _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Token *tokenPtr, int count,
			    CompileEnv *envPtr));
EXTERN int		TclCreateAuxData _ANSI_ARGS_((ClientData clientData,
			    AuxDataType *typePtr, CompileEnv *envPtr));
EXTERN int		TclCreateExceptRange _ANSI_ARGS_((
			    ExceptionRangeType type, CompileEnv *envPtr));
EXTERN ExecEnv *	TclCreateExecEnv _ANSI_ARGS_((Tcl_Interp *interp));
EXTERN void		TclDeleteExecEnv _ANSI_ARGS_((ExecEnv *eePtr));
EXTERN void		TclDeleteLiteralTable _ANSI_ARGS_((
			    Tcl_Interp *interp, LiteralTable *tablePtr));
EXTERN void		TclEmitForwardJump _ANSI_ARGS_((CompileEnv *envPtr,
			    TclJumpType jumpType, JumpFixup *jumpFixupPtr));
EXTERN ExceptionRange *	TclGetExceptionRangeForPc _ANSI_ARGS_((
			    unsigned char *pc, int catchOnly,
			    ByteCode* codePtr));
EXTERN void		TclExpandJumpFixupArray _ANSI_ARGS_((
                            JumpFixupArray *fixupArrayPtr));
EXTERN void		TclFinalizeAuxDataTypeTable _ANSI_ARGS_((void));
EXTERN int		TclFindCompiledLocal _ANSI_ARGS_((CONST char *name, 
        		    int nameChars, int create, int flags,
			    Proc *procPtr));
EXTERN LiteralEntry *	TclLookupLiteralEntry _ANSI_ARGS_((
			    Tcl_Interp *interp, Tcl_Obj *objPtr));
EXTERN int		TclFixupForwardJump _ANSI_ARGS_((
			    CompileEnv *envPtr, JumpFixup *jumpFixupPtr,
			    int jumpDist, int distThreshold));
EXTERN void		TclFreeCompileEnv _ANSI_ARGS_((CompileEnv *envPtr));







|
>




















|


|







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
EXTERN int		TclCompileExpr _ANSI_ARGS_((Tcl_Interp *interp,
			    CONST char *script, int numBytes,
			    CompileEnv *envPtr));
EXTERN int		TclCompileExprWords _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Token *tokenPtr, int numWords,
			    CompileEnv *envPtr));
EXTERN int		TclCompileScript _ANSI_ARGS_((Tcl_Interp *interp,
			    CONST char *script, int numBytes,
			    CompileEnv *envPtr));
EXTERN int		TclCompileScriptTokens _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Token *tokens, Tcl_Token *lastTokenPtr,
			    CompileEnv *envPtr));
EXTERN int		TclCompileTokens _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Token *tokenPtr, int count,
			    CompileEnv *envPtr));
EXTERN int		TclCreateAuxData _ANSI_ARGS_((ClientData clientData,
			    AuxDataType *typePtr, CompileEnv *envPtr));
EXTERN int		TclCreateExceptRange _ANSI_ARGS_((
			    ExceptionRangeType type, CompileEnv *envPtr));
EXTERN ExecEnv *	TclCreateExecEnv _ANSI_ARGS_((Tcl_Interp *interp));
EXTERN void		TclDeleteExecEnv _ANSI_ARGS_((ExecEnv *eePtr));
EXTERN void		TclDeleteLiteralTable _ANSI_ARGS_((
			    Tcl_Interp *interp, LiteralTable *tablePtr));
EXTERN void		TclEmitForwardJump _ANSI_ARGS_((CompileEnv *envPtr,
			    TclJumpType jumpType, JumpFixup *jumpFixupPtr));
EXTERN ExceptionRange *	TclGetExceptionRangeForPc _ANSI_ARGS_((
			    unsigned char *pc, int catchOnly,
			    ByteCode* codePtr));
EXTERN void		TclExpandJumpFixupArray _ANSI_ARGS_((
			    JumpFixupArray *fixupArrayPtr));
EXTERN void		TclFinalizeAuxDataTypeTable _ANSI_ARGS_((void));
EXTERN int		TclFindCompiledLocal _ANSI_ARGS_((CONST char *name, 
			    int nameChars, int create, int flags,
			    Proc *procPtr));
EXTERN LiteralEntry *	TclLookupLiteralEntry _ANSI_ARGS_((
			    Tcl_Interp *interp, Tcl_Obj *objPtr));
EXTERN int		TclFixupForwardJump _ANSI_ARGS_((
			    CompileEnv *envPtr, JumpFixup *jumpFixupPtr,
			    int jumpDist, int distThreshold));
EXTERN void		TclFreeCompileEnv _ANSI_ARGS_((CompileEnv *envPtr));
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
#ifdef TCL_COMPILE_STATS
EXTERN char *		TclLiteralStats _ANSI_ARGS_((
			    LiteralTable *tablePtr));
EXTERN int		TclLog2 _ANSI_ARGS_((int value));
#endif
#ifdef TCL_COMPILE_DEBUG
EXTERN void		TclPrintByteCodeObj _ANSI_ARGS_((Tcl_Interp *interp,
		            Tcl_Obj *objPtr));
#endif
EXTERN int		TclPrintInstruction _ANSI_ARGS_((ByteCode* codePtr,
			    unsigned char *pc));
EXTERN void		TclPrintObject _ANSI_ARGS_((FILE *outFile,
			    Tcl_Obj *objPtr, int maxChars));
EXTERN void		TclPrintSource _ANSI_ARGS_((FILE *outFile,
			    CONST char *string, int maxChars));







|







824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
#ifdef TCL_COMPILE_STATS
EXTERN char *		TclLiteralStats _ANSI_ARGS_((
			    LiteralTable *tablePtr));
EXTERN int		TclLog2 _ANSI_ARGS_((int value));
#endif
#ifdef TCL_COMPILE_DEBUG
EXTERN void		TclPrintByteCodeObj _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *objPtr));
#endif
EXTERN int		TclPrintInstruction _ANSI_ARGS_((ByteCode* codePtr,
			    unsigned char *pc));
EXTERN void		TclPrintObject _ANSI_ARGS_((FILE *outFile,
			    Tcl_Obj *objPtr, int maxChars));
EXTERN void		TclPrintSource _ANSI_ARGS_((FILE *outFile,
			    CONST char *string, int maxChars));
826
827
828
829
830
831
832


833
834
835
836
837
838
839
EXTERN void		TclVerifyGlobalLiteralTable _ANSI_ARGS_((
			    Interp *iPtr));
EXTERN void		TclVerifyLocalLiteralTable _ANSI_ARGS_((
			    CompileEnv *envPtr));
#endif
EXTERN int		TclCompileVariableCmd _ANSI_ARGS_((
			    Tcl_Interp *interp, Tcl_Parse *parsePtr, CompileEnv *envPtr));



/*
 *----------------------------------------------------------------
 * Macros used by Tcl bytecode compilation and execution modules
 * inside the Tcl core but not used outside.
 *----------------------------------------------------------------
 */







>
>







847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
EXTERN void		TclVerifyGlobalLiteralTable _ANSI_ARGS_((
			    Interp *iPtr));
EXTERN void		TclVerifyLocalLiteralTable _ANSI_ARGS_((
			    CompileEnv *envPtr));
#endif
EXTERN int		TclCompileVariableCmd _ANSI_ARGS_((
			    Tcl_Interp *interp, Tcl_Parse *parsePtr, CompileEnv *envPtr));
EXTERN int		TclWordKnownAtCompileTime _ANSI_ARGS_((
			    Tcl_Token *tokenPtr, Tcl_Obj *valuePtr));

/*
 *----------------------------------------------------------------
 * Macros used by Tcl bytecode compilation and execution modules
 * inside the Tcl core but not used outside.
 *----------------------------------------------------------------
 */
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
 *
 * EXTERN void	TclEmitOpcode _ANSI_ARGS_((unsigned char op,
 *		    CompileEnv *envPtr));
 */

#define TclEmitOpcode(op, envPtr) \
    if ((envPtr)->codeNext == (envPtr)->codeEnd) \
        TclExpandCodeArray(envPtr); \
    *(envPtr)->codeNext++ = (unsigned char) (op);\
    TclUpdateStackReqs(op, 0, envPtr)

/*
 * Macro to emit an integer operand.
 * The ANSI C "prototype" for this macro is:
 *
 * EXTERN void	TclEmitInt1 _ANSI_ARGS_((int i, CompileEnv *envPtr));

 */

#define TclEmitInt1(i, envPtr) \
    if ((envPtr)->codeNext == (envPtr)->codeEnd) \
        TclExpandCodeArray(envPtr); \
    *(envPtr)->codeNext++ = (unsigned char) ((unsigned int) (i))














/*
 * Macros to emit an instruction with signed or unsigned integer operands.
 * Four byte integers are stored in "big-endian" order with the high order
 * byte stored at the lowest address.
 * The ANSI C "prototypes" for these macros are:
 *
 * EXTERN void	TclEmitInstInt1 _ANSI_ARGS_((unsigned char op, int i, 
 *		    CompileEnv *envPtr));
 * EXTERN void	TclEmitInstInt4 _ANSI_ARGS_((unsigned char op, int i, 
 *		    CompileEnv *envPtr));
 */


#define TclEmitInstInt1(op, i, envPtr) \
    if (((envPtr)->codeNext + 2) > (envPtr)->codeEnd) { \
        TclExpandCodeArray(envPtr); \
    } \
    *(envPtr)->codeNext++ = (unsigned char) (op); \
    *(envPtr)->codeNext++ = (unsigned char) ((unsigned int) (i));\
    TclUpdateStackReqs(op, i, envPtr)

#define TclEmitInstInt4(op, i, envPtr) \
    if (((envPtr)->codeNext + 5) > (envPtr)->codeEnd) { \
        TclExpandCodeArray(envPtr); \
    } \
    *(envPtr)->codeNext++ = (unsigned char) (op); \
    *(envPtr)->codeNext++ = \
        (unsigned char) ((unsigned int) (i) >> 24); \
    *(envPtr)->codeNext++ = \
        (unsigned char) ((unsigned int) (i) >> 16); \
    *(envPtr)->codeNext++ = \
        (unsigned char) ((unsigned int) (i) >>  8); \
    *(envPtr)->codeNext++ = \
        (unsigned char) ((unsigned int) (i)      );\
    TclUpdateStackReqs(op, i, envPtr)
    



















/*
 * Macro to push a Tcl object onto the Tcl evaluation stack. It emits the
 * object's one or four byte array index into the CompileEnv's code
 * array. These support, respectively, a maximum of 256 (2**8) and 2**32
 * objects in a CompileEnv. The ANSI C "prototype" for this macro is:
 *
 * EXTERN void	TclEmitPush _ANSI_ARGS_((int objIndex, CompileEnv *envPtr));
 */

#define TclEmitPush(objIndex, envPtr) \
    {\
        register int objIndexCopy = (objIndex);\
        if (objIndexCopy <= 255) { \
	    TclEmitInstInt1(INST_PUSH1, objIndexCopy, (envPtr)); \
        } else { \
	    TclEmitInstInt4(INST_PUSH4, objIndexCopy, (envPtr)); \
	}\
    }

/*
 * Macros to update a (signed or unsigned) integer starting at a pointer.
 * The two variants depend on the number of bytes. The ANSI C "prototypes"
 * for these macros are:
 *
 * EXTERN void	TclStoreInt1AtPtr _ANSI_ARGS_((int i, unsigned char *p));
 * EXTERN void	TclStoreInt4AtPtr _ANSI_ARGS_((int i, unsigned char *p));
 */
    
#define TclStoreInt1AtPtr(i, p) \
    *(p)   = (unsigned char) ((unsigned int) (i))
    
#define TclStoreInt4AtPtr(i, p) \
    *(p)   = (unsigned char) ((unsigned int) (i) >> 24); \
    *(p+1) = (unsigned char) ((unsigned int) (i) >> 16); \
    *(p+2) = (unsigned char) ((unsigned int) (i) >>  8); \
    *(p+3) = (unsigned char) ((unsigned int) (i)      )

/*







|




|
|


>




|


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















|







|



|

|

|

|

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











|
|

|












|


|







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
 *
 * EXTERN void	TclEmitOpcode _ANSI_ARGS_((unsigned char op,
 *		    CompileEnv *envPtr));
 */

#define TclEmitOpcode(op, envPtr) \
    if ((envPtr)->codeNext == (envPtr)->codeEnd) \
	TclExpandCodeArray(envPtr); \
    *(envPtr)->codeNext++ = (unsigned char) (op);\
    TclUpdateStackReqs(op, 0, envPtr)

/*
 * Macros to emit an integer operand.
 * The ANSI C "prototype" for these macros are:
 *
 * EXTERN void	TclEmitInt1 _ANSI_ARGS_((int i, CompileEnv *envPtr));
 * EXTERN void	TclEmitInt4 _ANSI_ARGS_((int i, CompileEnv *envPtr));
 */

#define TclEmitInt1(i, envPtr) \
    if ((envPtr)->codeNext == (envPtr)->codeEnd) \
	TclExpandCodeArray(envPtr); \
    *(envPtr)->codeNext++ = (unsigned char) ((unsigned int) (i))

#define TclEmitInt4(i, envPtr) \
    if (((envPtr)->codeNext + 4) > (envPtr)->codeEnd) { \
	TclExpandCodeArray(envPtr); \
    } \
    *(envPtr)->codeNext++ = \
	(unsigned char) ((unsigned int) (i) >> 24); \
    *(envPtr)->codeNext++ = \
	(unsigned char) ((unsigned int) (i) >> 16); \
    *(envPtr)->codeNext++ = \
	(unsigned char) ((unsigned int) (i) >>  8); \
    *(envPtr)->codeNext++ = \
	(unsigned char) ((unsigned int) (i)      )

/*
 * Macros to emit an instruction with signed or unsigned integer operands.
 * Four byte integers are stored in "big-endian" order with the high order
 * byte stored at the lowest address.
 * The ANSI C "prototypes" for these macros are:
 *
 * EXTERN void	TclEmitInstInt1 _ANSI_ARGS_((unsigned char op, int i, 
 *		    CompileEnv *envPtr));
 * EXTERN void	TclEmitInstInt4 _ANSI_ARGS_((unsigned char op, int i, 
 *		    CompileEnv *envPtr));
 */


#define TclEmitInstInt1(op, i, envPtr) \
    if (((envPtr)->codeNext + 2) > (envPtr)->codeEnd) { \
	TclExpandCodeArray(envPtr); \
    } \
    *(envPtr)->codeNext++ = (unsigned char) (op); \
    *(envPtr)->codeNext++ = (unsigned char) ((unsigned int) (i));\
    TclUpdateStackReqs(op, i, envPtr)

#define TclEmitInstInt4(op, i, envPtr) \
    if (((envPtr)->codeNext + 5) > (envPtr)->codeEnd) { \
	TclExpandCodeArray(envPtr); \
    } \
    *(envPtr)->codeNext++ = (unsigned char) (op); \
    *(envPtr)->codeNext++ = \
	(unsigned char) ((unsigned int) (i) >> 24); \
    *(envPtr)->codeNext++ = \
	(unsigned char) ((unsigned int) (i) >> 16); \
    *(envPtr)->codeNext++ = \
	(unsigned char) ((unsigned int) (i) >>  8); \
    *(envPtr)->codeNext++ = \
	(unsigned char) ((unsigned int) (i)      );\
    TclUpdateStackReqs(op, i, envPtr)

/*
 * Macro to emit an immediate list of index deltas in the code stream. 
 * The ANSI C "prototypes" for this macro is:
 *
 * EXTERN void	TclEmitImmList1 _ANSI_ARGS_((Tcl_Obj *listPtr,
 *		    CompileEnv *envPtr));
 */

#define TclEmitImmDeltaList1(listPtr, envPtr)				\
    {									\
	int numBytes = Tcl_DStringLength(listPtr) + 1;			\
	while (((envPtr)->codeNext + numBytes) > (envPtr)->codeEnd) {	\
	    TclExpandCodeArray(envPtr);					\
	}								\
	memcpy((VOID *) (envPtr)->codeNext,				\
		(VOID *)Tcl_DStringValue(listPtr), (size_t) numBytes);	\
	(envPtr)->codeNext += numBytes;					\
    }

/*
 * Macro to push a Tcl object onto the Tcl evaluation stack. It emits the
 * object's one or four byte array index into the CompileEnv's code
 * array. These support, respectively, a maximum of 256 (2**8) and 2**32
 * objects in a CompileEnv. The ANSI C "prototype" for this macro is:
 *
 * EXTERN void	TclEmitPush _ANSI_ARGS_((int objIndex, CompileEnv *envPtr));
 */

#define TclEmitPush(objIndex, envPtr) \
    {\
	register int objIndexCopy = (objIndex);\
	if (objIndexCopy <= 255) { \
	    TclEmitInstInt1(INST_PUSH1, objIndexCopy, (envPtr)); \
	} else { \
	    TclEmitInstInt4(INST_PUSH4, objIndexCopy, (envPtr)); \
	}\
    }

/*
 * Macros to update a (signed or unsigned) integer starting at a pointer.
 * The two variants depend on the number of bytes. The ANSI C "prototypes"
 * for these macros are:
 *
 * EXTERN void	TclStoreInt1AtPtr _ANSI_ARGS_((int i, unsigned char *p));
 * EXTERN void	TclStoreInt4AtPtr _ANSI_ARGS_((int i, unsigned char *p));
 */

#define TclStoreInt1AtPtr(i, p) \
    *(p)   = (unsigned char) ((unsigned int) (i))

#define TclStoreInt4AtPtr(i, p) \
    *(p)   = (unsigned char) ((unsigned int) (i) >> 24); \
    *(p+1) = (unsigned char) ((unsigned int) (i) >> 16); \
    *(p+2) = (unsigned char) ((unsigned int) (i) >>  8); \
    *(p+3) = (unsigned char) ((unsigned int) (i)      )

/*
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
 *		    JumpFixup *fixupPtr, int threshold));
 */

#define TclFixupForwardJumpToHere(envPtr, fixupPtr, threshold) \
    TclFixupForwardJump((envPtr), (fixupPtr), \
	    (envPtr)->codeNext-(envPtr)->codeStart-(fixupPtr)->codeOffset, \
	    (threshold))
    
/*
 * Macros to get a signed integer (GET_INT{1,2}) or an unsigned int
 * (GET_UINT{1,2}) from a pointer. There are two variants for each
 * return type that depend on the number of bytes fetched.
 * The ANSI C "prototypes" for these macros are:
 *
 * EXTERN int	        TclGetInt1AtPtr  _ANSI_ARGS_((unsigned char *p));
 * EXTERN int	        TclGetInt4AtPtr  _ANSI_ARGS_((unsigned char *p));
 * EXTERN unsigned int	TclGetUInt1AtPtr _ANSI_ARGS_((unsigned char *p));
 * EXTERN unsigned int	TclGetUInt4AtPtr _ANSI_ARGS_((unsigned char *p));
 */

/*
 * The TclGetInt1AtPtr macro is tricky because we want to do sign
 * extension on the 1-byte value. Unfortunately the "char" type isn't







|






|
|







1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
 *		    JumpFixup *fixupPtr, int threshold));
 */

#define TclFixupForwardJumpToHere(envPtr, fixupPtr, threshold) \
    TclFixupForwardJump((envPtr), (fixupPtr), \
	    (envPtr)->codeNext-(envPtr)->codeStart-(fixupPtr)->codeOffset, \
	    (threshold))

/*
 * Macros to get a signed integer (GET_INT{1,2}) or an unsigned int
 * (GET_UINT{1,2}) from a pointer. There are two variants for each
 * return type that depend on the number of bytes fetched.
 * The ANSI C "prototypes" for these macros are:
 *
 * EXTERN int		TclGetInt1AtPtr  _ANSI_ARGS_((unsigned char *p));
 * EXTERN int		TclGetInt4AtPtr  _ANSI_ARGS_((unsigned char *p));
 * EXTERN unsigned int	TclGetUInt1AtPtr _ANSI_ARGS_((unsigned char *p));
 * EXTERN unsigned int	TclGetUInt4AtPtr _ANSI_ARGS_((unsigned char *p));
 */

/*
 * The TclGetInt1AtPtr macro is tricky because we want to do sign
 * extension on the 1-byte value. Unfortunately the "char" type isn't
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
#    else
#	define TclGetInt1AtPtr(p) (((int) *((char *) p)) \
		| ((*(p) & 0200) ? (-256) : 0))
#    endif
#endif

#define TclGetInt4AtPtr(p) (((int) TclGetInt1AtPtr(p) << 24) | \
		                  	    (*((p)+1) << 16) | \
				  	    (*((p)+2) <<  8) | \
				  	    (*((p)+3)))

#define TclGetUInt1AtPtr(p) ((unsigned int) *(p))
#define TclGetUInt4AtPtr(p) ((unsigned int) (*(p)     << 24) | \
		                            (*((p)+1) << 16) | \
				            (*((p)+2) <<  8) | \
				            (*((p)+3)))

/*
 * Macros used to compute the minimum and maximum of two integers.
 * The ANSI C "prototypes" for these macros are:
 *
 * EXTERN int  TclMin _ANSI_ARGS_((int i, int j));
 * EXTERN int  TclMax _ANSI_ARGS_((int i, int j));







|





|
|
|







1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
#    else
#	define TclGetInt1AtPtr(p) (((int) *((char *) p)) \
		| ((*(p) & 0200) ? (-256) : 0))
#    endif
#endif

#define TclGetInt4AtPtr(p) (((int) TclGetInt1AtPtr(p) << 24) | \
					    (*((p)+1) << 16) | \
				  	    (*((p)+2) <<  8) | \
				  	    (*((p)+3)))

#define TclGetUInt1AtPtr(p) ((unsigned int) *(p))
#define TclGetUInt4AtPtr(p) ((unsigned int) (*(p)     << 24) | \
					    (*((p)+1) << 16) | \
					    (*((p)+2) <<  8) | \
					    (*((p)+3)))

/*
 * Macros used to compute the minimum and maximum of two integers.
 * The ANSI C "prototypes" for these macros are:
 *
 * EXTERN int  TclMin _ANSI_ARGS_((int i, int j));
 * EXTERN int  TclMax _ANSI_ARGS_((int i, int j));
Changes to generic/tclConfig.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclConfig.c --
 *
 *	This file provides the facilities which allow Tcl and other packages
 *	to embed configuration information into their binary libraries.
 *
 * Copyright (c) 2002 Andreas Kupries <andreas_kupries@users.sourceforge.net>
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclConfig.c,v 1.3.2.1 2003/06/18 19:48:00 dgp Exp $
 */

#include "tclInt.h"



/*











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclConfig.c --
 *
 *	This file provides the facilities which allow Tcl and other packages
 *	to embed configuration information into their binary libraries.
 *
 * Copyright (c) 2002 Andreas Kupries <andreas_kupries@users.sourceforge.net>
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclConfig.c,v 1.3.2.2 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"



/*
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
 * Side effects:
 *	See the manual for what this command does.
 *
 *----------------------------------------------------------------------
 */

static int
QueryConfigObjCmd (clientData, interp, objc, objv)
     ClientData clientData;
     Tcl_Interp *interp;
     int objc;
     struct Tcl_Obj * CONST * objv;
{
    Tcl_Obj* pkgName = (Tcl_Obj*) clientData;
    Tcl_Obj* pDB;
    Tcl_Obj* pkgDict;
    Tcl_Obj* val;
    Tcl_DictSearch s;
    int n, i, res, done, index;
    Tcl_Obj* key;
    Tcl_Obj** vals;

    static CONST char *subcmdStrings[] = {
	"get", "list", NULL
    };
    enum subcmds {
      CFG_GET, CFG_LIST
    };

    if ((objc < 2) || (objc > 3)) {
        Tcl_WrongNumArgs (interp, 0, NULL, "list | get key");
	return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[1], subcmdStrings,
	   "subcommand", 0, &index) != TCL_OK) {
	return TCL_ERROR;
    }

    pDB = GetConfigDict (interp);
    res = Tcl_DictObjGet (interp, pDB, pkgName, &pkgDict);
    if ((res != TCL_OK) || (pkgDict == NULL)) {
        /* Maybe a panic is better, because the package data has to be present */
        Tcl_SetObjResult (interp, Tcl_NewStringObj ("package not known", -1));
	return TCL_ERROR;
    }

    switch ((enum subcmds) index) {
        case CFG_GET:
	    if (objc != 3) {
	        Tcl_WrongNumArgs (interp, 0, NULL, "get key");
		return TCL_ERROR;
	    }

	    res = Tcl_DictObjGet (interp, pkgDict, objv [2], &val);
	    if ((res != TCL_OK) || (val == NULL)) {
	        Tcl_SetObjResult (interp, Tcl_NewStringObj ("key not known", -1));
		return TCL_ERROR;
	    }

	    Tcl_SetObjResult (interp, val);
	    return TCL_OK;


        case CFG_LIST:
	    if (objc != 2) {
	        Tcl_WrongNumArgs (interp, 0, NULL, "list");
		return TCL_ERROR;
	    }

	    Tcl_DictObjSize (interp, pkgDict, &n);
	    if (n == 0) {
	        Tcl_SetObjResult (interp, Tcl_NewListObj (0, NULL));
	        return TCL_OK;
	    }

	    vals = (Tcl_Obj**) ckalloc (n * sizeof (Tcl_Obj*));

	    for (i = 0, Tcl_DictObjFirst(interp, pkgDict, &s, &key, NULL, &done);
		 !done;
		 Tcl_DictObjNext (&s, &key, NULL, &done), i++) {
	        if (done) break;
		vals [i] = key;
	    }
	    Tcl_DictObjDone (&s);

	    Tcl_SetObjResult (interp, Tcl_NewListObj (n, vals));
	    ckfree ((char*) vals);

	    return TCL_OK;

        default:
	    Tcl_Panic ("QueryConfigObjCmd: Unknown subcommand to 'pkgconfig'. This can't happen");
	    break;
    }
    return TCL_ERROR;
}

/*
 *-------------------------------------------------------------------------
 *







|



|

|
|
<
<


|
<





|











|
|
|
|
|




|
|
|
|
|

|
|
|
|
|

|
|

<
|
|
|
|
|

|
|
|
|
|

|

|
<
|
<
|
|
<

<
<
|
|

|
|
|







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
 * Side effects:
 *	See the manual for what this command does.
 *
 *----------------------------------------------------------------------
 */

static int
QueryConfigObjCmd(clientData, interp, objc, objv)
     ClientData clientData;
     Tcl_Interp *interp;
     int objc;
     struct Tcl_Obj * CONST *objv;
{
    Tcl_Obj *pkgName = (Tcl_Obj*) clientData;
    Tcl_Obj *pDB, *pkgDict, *val;


    Tcl_DictSearch s;
    int n, i, res, done, index;
    Tcl_Obj *key, **vals;


    static CONST char *subcmdStrings[] = {
	"get", "list", NULL
    };
    enum subcmds {
	CFG_GET, CFG_LIST
    };

    if ((objc < 2) || (objc > 3)) {
        Tcl_WrongNumArgs (interp, 0, NULL, "list | get key");
	return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[1], subcmdStrings,
	   "subcommand", 0, &index) != TCL_OK) {
	return TCL_ERROR;
    }

    pDB = GetConfigDict(interp);
    res = Tcl_DictObjGet(interp, pDB, pkgName, &pkgDict);
    if (res!=TCL_OK || pkgDict==NULL) {
        /* Maybe a Tcl_Panic is better, because the package data has to be present */
        Tcl_SetObjResult(interp, Tcl_NewStringObj("package not known", -1));
	return TCL_ERROR;
    }

    switch ((enum subcmds) index) {
    case CFG_GET:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 0, NULL, "get key");
	    return TCL_ERROR;
	}

	res = Tcl_DictObjGet(interp, pkgDict, objv [2], &val);
	if (res!=TCL_OK || val==NULL) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj("key not known", -1));
	    return TCL_ERROR;
	}

	Tcl_SetObjResult(interp, val);
	return TCL_OK;


    case CFG_LIST:
	if (objc != 2) {
	    Tcl_WrongNumArgs(interp, 0, NULL, "list");
	    return TCL_ERROR;
	}

	Tcl_DictObjSize(interp, pkgDict, &n);
	if (n == 0) {
	    Tcl_SetObjResult(interp, Tcl_NewListObj(0, NULL));
	    return TCL_OK;
	}

	vals = (Tcl_Obj**) ckalloc(n * sizeof(Tcl_Obj*));

	for (i=0, Tcl_DictObjFirst(interp, pkgDict, &s, &key, NULL, &done);

		!done; Tcl_DictObjNext(&s, &key, NULL, &done), i++) {

	    vals[i] = key;
	}




	Tcl_SetObjResult(interp, TclNewListObjDirect(n, vals));
	return TCL_OK;

    default:
	Tcl_Panic("QueryConfigObjCmd: Unknown subcommand to 'pkgconfig'. This can't happen");
	break;
    }
    return TCL_ERROR;
}

/*
 *-------------------------------------------------------------------------
 *
Changes to generic/tclDecls.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
 * tclDecls.h --
 *
 *	Declarations of functions in the platform independent public Tcl API.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclDecls.h,v 1.95.2.6 2003/10/16 02:29:16 dgp Exp $
 */

#ifndef _TCLDECLS
#define _TCLDECLS

/*
 * WARNING: This file is automatically generated by the tools/genStubs.tcl










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
 * tclDecls.h --
 *
 *	Declarations of functions in the platform independent public Tcl API.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclDecls.h,v 1.95.2.7 2004/02/07 05:48:00 dgp Exp $
 */

#ifndef _TCLDECLS
#define _TCLDECLS

/*
 * WARNING: This file is automatically generated by the tools/genStubs.tcl
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
EXTERN int		Tcl_FSEqualPaths _ANSI_ARGS_((Tcl_Obj* firstPtr, 
				Tcl_Obj* secondPtr));
#endif
#ifndef Tcl_FSGetNormalizedPath_TCL_DECLARED
#define Tcl_FSGetNormalizedPath_TCL_DECLARED
/* 463 */
EXTERN Tcl_Obj*		Tcl_FSGetNormalizedPath _ANSI_ARGS_((
				Tcl_Interp * interp, Tcl_Obj* pathObjPtr));
#endif
#ifndef Tcl_FSJoinToPath_TCL_DECLARED
#define Tcl_FSJoinToPath_TCL_DECLARED
/* 464 */
EXTERN Tcl_Obj*		Tcl_FSJoinToPath _ANSI_ARGS_((Tcl_Obj * basePtr, 
				int objc, Tcl_Obj *CONST objv[]));
#endif
#ifndef Tcl_FSGetInternalRep_TCL_DECLARED
#define Tcl_FSGetInternalRep_TCL_DECLARED
/* 465 */
EXTERN ClientData	Tcl_FSGetInternalRep _ANSI_ARGS_((
				Tcl_Obj* pathObjPtr, Tcl_Filesystem * fsPtr));
#endif
#ifndef Tcl_FSGetTranslatedPath_TCL_DECLARED
#define Tcl_FSGetTranslatedPath_TCL_DECLARED
/* 466 */
EXTERN Tcl_Obj*		Tcl_FSGetTranslatedPath _ANSI_ARGS_((
				Tcl_Interp * interp, Tcl_Obj* pathPtr));
#endif







|




|





|
|







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
EXTERN int		Tcl_FSEqualPaths _ANSI_ARGS_((Tcl_Obj* firstPtr, 
				Tcl_Obj* secondPtr));
#endif
#ifndef Tcl_FSGetNormalizedPath_TCL_DECLARED
#define Tcl_FSGetNormalizedPath_TCL_DECLARED
/* 463 */
EXTERN Tcl_Obj*		Tcl_FSGetNormalizedPath _ANSI_ARGS_((
				Tcl_Interp * interp, Tcl_Obj* pathPtr));
#endif
#ifndef Tcl_FSJoinToPath_TCL_DECLARED
#define Tcl_FSJoinToPath_TCL_DECLARED
/* 464 */
EXTERN Tcl_Obj*		Tcl_FSJoinToPath _ANSI_ARGS_((Tcl_Obj * pathPtr, 
				int objc, Tcl_Obj *CONST objv[]));
#endif
#ifndef Tcl_FSGetInternalRep_TCL_DECLARED
#define Tcl_FSGetInternalRep_TCL_DECLARED
/* 465 */
EXTERN ClientData	Tcl_FSGetInternalRep _ANSI_ARGS_((Tcl_Obj* pathPtr, 
				Tcl_Filesystem * fsPtr));
#endif
#ifndef Tcl_FSGetTranslatedPath_TCL_DECLARED
#define Tcl_FSGetTranslatedPath_TCL_DECLARED
/* 466 */
EXTERN Tcl_Obj*		Tcl_FSGetTranslatedPath _ANSI_ARGS_((
				Tcl_Interp * interp, Tcl_Obj* pathPtr));
#endif
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
EXTERN Tcl_Obj*		Tcl_FSNewNativePath _ANSI_ARGS_((
				Tcl_Filesystem* fromFilesystem, 
				ClientData clientData));
#endif
#ifndef Tcl_FSGetNativePath_TCL_DECLARED
#define Tcl_FSGetNativePath_TCL_DECLARED
/* 469 */
EXTERN CONST char*	Tcl_FSGetNativePath _ANSI_ARGS_((Tcl_Obj* pathObjPtr));
#endif
#ifndef Tcl_FSFileSystemInfo_TCL_DECLARED
#define Tcl_FSFileSystemInfo_TCL_DECLARED
/* 470 */
EXTERN Tcl_Obj*		Tcl_FSFileSystemInfo _ANSI_ARGS_((
				Tcl_Obj* pathObjPtr));
#endif
#ifndef Tcl_FSPathSeparator_TCL_DECLARED
#define Tcl_FSPathSeparator_TCL_DECLARED
/* 471 */
EXTERN Tcl_Obj*		Tcl_FSPathSeparator _ANSI_ARGS_((Tcl_Obj* pathObjPtr));
#endif
#ifndef Tcl_FSListVolumes_TCL_DECLARED
#define Tcl_FSListVolumes_TCL_DECLARED
/* 472 */
EXTERN Tcl_Obj*		Tcl_FSListVolumes _ANSI_ARGS_((void));
#endif
#ifndef Tcl_FSRegister_TCL_DECLARED







|




|
<




|







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
EXTERN Tcl_Obj*		Tcl_FSNewNativePath _ANSI_ARGS_((
				Tcl_Filesystem* fromFilesystem, 
				ClientData clientData));
#endif
#ifndef Tcl_FSGetNativePath_TCL_DECLARED
#define Tcl_FSGetNativePath_TCL_DECLARED
/* 469 */
EXTERN CONST char*	Tcl_FSGetNativePath _ANSI_ARGS_((Tcl_Obj* pathPtr));
#endif
#ifndef Tcl_FSFileSystemInfo_TCL_DECLARED
#define Tcl_FSFileSystemInfo_TCL_DECLARED
/* 470 */
EXTERN Tcl_Obj*		Tcl_FSFileSystemInfo _ANSI_ARGS_((Tcl_Obj* pathPtr));

#endif
#ifndef Tcl_FSPathSeparator_TCL_DECLARED
#define Tcl_FSPathSeparator_TCL_DECLARED
/* 471 */
EXTERN Tcl_Obj*		Tcl_FSPathSeparator _ANSI_ARGS_((Tcl_Obj* pathPtr));
#endif
#ifndef Tcl_FSListVolumes_TCL_DECLARED
#define Tcl_FSListVolumes_TCL_DECLARED
/* 472 */
EXTERN Tcl_Obj*		Tcl_FSListVolumes _ANSI_ARGS_((void));
#endif
#ifndef Tcl_FSRegister_TCL_DECLARED
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
EXTERN CONST char*	Tcl_FSGetTranslatedStringPath _ANSI_ARGS_((
				Tcl_Interp * interp, Tcl_Obj* pathPtr));
#endif
#ifndef Tcl_FSGetFileSystemForPath_TCL_DECLARED
#define Tcl_FSGetFileSystemForPath_TCL_DECLARED
/* 477 */
EXTERN Tcl_Filesystem*	Tcl_FSGetFileSystemForPath _ANSI_ARGS_((
				Tcl_Obj* pathObjPtr));
#endif
#ifndef Tcl_FSGetPathType_TCL_DECLARED
#define Tcl_FSGetPathType_TCL_DECLARED
/* 478 */
EXTERN Tcl_PathType	Tcl_FSGetPathType _ANSI_ARGS_((Tcl_Obj * pathObjPtr));
#endif
#ifndef Tcl_OutputBuffered_TCL_DECLARED
#define Tcl_OutputBuffered_TCL_DECLARED
/* 479 */
EXTERN int		Tcl_OutputBuffered _ANSI_ARGS_((Tcl_Channel chan));
#endif
#ifndef Tcl_FSMountsChanged_TCL_DECLARED







|




|







2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
EXTERN CONST char*	Tcl_FSGetTranslatedStringPath _ANSI_ARGS_((
				Tcl_Interp * interp, Tcl_Obj* pathPtr));
#endif
#ifndef Tcl_FSGetFileSystemForPath_TCL_DECLARED
#define Tcl_FSGetFileSystemForPath_TCL_DECLARED
/* 477 */
EXTERN Tcl_Filesystem*	Tcl_FSGetFileSystemForPath _ANSI_ARGS_((
				Tcl_Obj* pathPtr));
#endif
#ifndef Tcl_FSGetPathType_TCL_DECLARED
#define Tcl_FSGetPathType_TCL_DECLARED
/* 478 */
EXTERN Tcl_PathType	Tcl_FSGetPathType _ANSI_ARGS_((Tcl_Obj * pathPtr));
#endif
#ifndef Tcl_OutputBuffered_TCL_DECLARED
#define Tcl_OutputBuffered_TCL_DECLARED
/* 479 */
EXTERN int		Tcl_OutputBuffered _ANSI_ARGS_((Tcl_Channel chan));
#endif
#ifndef Tcl_FSMountsChanged_TCL_DECLARED
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
    Tcl_Channel (*tcl_FSOpenFileChannel) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * pathPtr, CONST char * modeString, int permissions)); /* 456 */
    Tcl_Obj* (*tcl_FSGetCwd) _ANSI_ARGS_((Tcl_Interp * interp)); /* 457 */
    int (*tcl_FSChdir) _ANSI_ARGS_((Tcl_Obj * pathPtr)); /* 458 */
    int (*tcl_FSConvertToPathType) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * pathPtr)); /* 459 */
    Tcl_Obj* (*tcl_FSJoinPath) _ANSI_ARGS_((Tcl_Obj * listObj, int elements)); /* 460 */
    Tcl_Obj* (*tcl_FSSplitPath) _ANSI_ARGS_((Tcl_Obj* pathPtr, int * lenPtr)); /* 461 */
    int (*tcl_FSEqualPaths) _ANSI_ARGS_((Tcl_Obj* firstPtr, Tcl_Obj* secondPtr)); /* 462 */
    Tcl_Obj* (*tcl_FSGetNormalizedPath) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj* pathObjPtr)); /* 463 */
    Tcl_Obj* (*tcl_FSJoinToPath) _ANSI_ARGS_((Tcl_Obj * basePtr, int objc, Tcl_Obj *CONST objv[])); /* 464 */
    ClientData (*tcl_FSGetInternalRep) _ANSI_ARGS_((Tcl_Obj* pathObjPtr, Tcl_Filesystem * fsPtr)); /* 465 */
    Tcl_Obj* (*tcl_FSGetTranslatedPath) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj* pathPtr)); /* 466 */
    int (*tcl_FSEvalFile) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * fileName)); /* 467 */
    Tcl_Obj* (*tcl_FSNewNativePath) _ANSI_ARGS_((Tcl_Filesystem* fromFilesystem, ClientData clientData)); /* 468 */
    CONST char* (*tcl_FSGetNativePath) _ANSI_ARGS_((Tcl_Obj* pathObjPtr)); /* 469 */
    Tcl_Obj* (*tcl_FSFileSystemInfo) _ANSI_ARGS_((Tcl_Obj* pathObjPtr)); /* 470 */
    Tcl_Obj* (*tcl_FSPathSeparator) _ANSI_ARGS_((Tcl_Obj* pathObjPtr)); /* 471 */
    Tcl_Obj* (*tcl_FSListVolumes) _ANSI_ARGS_((void)); /* 472 */
    int (*tcl_FSRegister) _ANSI_ARGS_((ClientData clientData, Tcl_Filesystem * fsPtr)); /* 473 */
    int (*tcl_FSUnregister) _ANSI_ARGS_((Tcl_Filesystem * fsPtr)); /* 474 */
    ClientData (*tcl_FSData) _ANSI_ARGS_((Tcl_Filesystem * fsPtr)); /* 475 */
    CONST char* (*tcl_FSGetTranslatedStringPath) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj* pathPtr)); /* 476 */
    Tcl_Filesystem* (*tcl_FSGetFileSystemForPath) _ANSI_ARGS_((Tcl_Obj* pathObjPtr)); /* 477 */
    Tcl_PathType (*tcl_FSGetPathType) _ANSI_ARGS_((Tcl_Obj * pathObjPtr)); /* 478 */
    int (*tcl_OutputBuffered) _ANSI_ARGS_((Tcl_Channel chan)); /* 479 */
    void (*tcl_FSMountsChanged) _ANSI_ARGS_((Tcl_Filesystem * fsPtr)); /* 480 */
    int (*tcl_EvalTokensStandard) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Token * tokenPtr, int count)); /* 481 */
    void (*tcl_GetTime) _ANSI_ARGS_((Tcl_Time* timeBuf)); /* 482 */
    Tcl_Trace (*tcl_CreateObjTrace) _ANSI_ARGS_((Tcl_Interp* interp, int level, int flags, Tcl_CmdObjTraceProc* objProc, ClientData clientData, Tcl_CmdObjTraceDeleteProc* delProc)); /* 483 */
    int (*tcl_GetCommandInfoFromToken) _ANSI_ARGS_((Tcl_Command token, Tcl_CmdInfo* infoPtr)); /* 484 */
    int (*tcl_SetCommandInfoFromToken) _ANSI_ARGS_((Tcl_Command token, CONST Tcl_CmdInfo* infoPtr)); /* 485 */







|
|
|



|
|
|





|
|







3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
    Tcl_Channel (*tcl_FSOpenFileChannel) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * pathPtr, CONST char * modeString, int permissions)); /* 456 */
    Tcl_Obj* (*tcl_FSGetCwd) _ANSI_ARGS_((Tcl_Interp * interp)); /* 457 */
    int (*tcl_FSChdir) _ANSI_ARGS_((Tcl_Obj * pathPtr)); /* 458 */
    int (*tcl_FSConvertToPathType) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * pathPtr)); /* 459 */
    Tcl_Obj* (*tcl_FSJoinPath) _ANSI_ARGS_((Tcl_Obj * listObj, int elements)); /* 460 */
    Tcl_Obj* (*tcl_FSSplitPath) _ANSI_ARGS_((Tcl_Obj* pathPtr, int * lenPtr)); /* 461 */
    int (*tcl_FSEqualPaths) _ANSI_ARGS_((Tcl_Obj* firstPtr, Tcl_Obj* secondPtr)); /* 462 */
    Tcl_Obj* (*tcl_FSGetNormalizedPath) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj* pathPtr)); /* 463 */
    Tcl_Obj* (*tcl_FSJoinToPath) _ANSI_ARGS_((Tcl_Obj * pathPtr, int objc, Tcl_Obj *CONST objv[])); /* 464 */
    ClientData (*tcl_FSGetInternalRep) _ANSI_ARGS_((Tcl_Obj* pathPtr, Tcl_Filesystem * fsPtr)); /* 465 */
    Tcl_Obj* (*tcl_FSGetTranslatedPath) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj* pathPtr)); /* 466 */
    int (*tcl_FSEvalFile) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * fileName)); /* 467 */
    Tcl_Obj* (*tcl_FSNewNativePath) _ANSI_ARGS_((Tcl_Filesystem* fromFilesystem, ClientData clientData)); /* 468 */
    CONST char* (*tcl_FSGetNativePath) _ANSI_ARGS_((Tcl_Obj* pathPtr)); /* 469 */
    Tcl_Obj* (*tcl_FSFileSystemInfo) _ANSI_ARGS_((Tcl_Obj* pathPtr)); /* 470 */
    Tcl_Obj* (*tcl_FSPathSeparator) _ANSI_ARGS_((Tcl_Obj* pathPtr)); /* 471 */
    Tcl_Obj* (*tcl_FSListVolumes) _ANSI_ARGS_((void)); /* 472 */
    int (*tcl_FSRegister) _ANSI_ARGS_((ClientData clientData, Tcl_Filesystem * fsPtr)); /* 473 */
    int (*tcl_FSUnregister) _ANSI_ARGS_((Tcl_Filesystem * fsPtr)); /* 474 */
    ClientData (*tcl_FSData) _ANSI_ARGS_((Tcl_Filesystem * fsPtr)); /* 475 */
    CONST char* (*tcl_FSGetTranslatedStringPath) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj* pathPtr)); /* 476 */
    Tcl_Filesystem* (*tcl_FSGetFileSystemForPath) _ANSI_ARGS_((Tcl_Obj* pathPtr)); /* 477 */
    Tcl_PathType (*tcl_FSGetPathType) _ANSI_ARGS_((Tcl_Obj * pathPtr)); /* 478 */
    int (*tcl_OutputBuffered) _ANSI_ARGS_((Tcl_Channel chan)); /* 479 */
    void (*tcl_FSMountsChanged) _ANSI_ARGS_((Tcl_Filesystem * fsPtr)); /* 480 */
    int (*tcl_EvalTokensStandard) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Token * tokenPtr, int count)); /* 481 */
    void (*tcl_GetTime) _ANSI_ARGS_((Tcl_Time* timeBuf)); /* 482 */
    Tcl_Trace (*tcl_CreateObjTrace) _ANSI_ARGS_((Tcl_Interp* interp, int level, int flags, Tcl_CmdObjTraceProc* objProc, ClientData clientData, Tcl_CmdObjTraceDeleteProc* delProc)); /* 483 */
    int (*tcl_GetCommandInfoFromToken) _ANSI_ARGS_((Tcl_Command token, Tcl_CmdInfo* infoPtr)); /* 484 */
    int (*tcl_SetCommandInfoFromToken) _ANSI_ARGS_((Tcl_Command token, CONST Tcl_CmdInfo* infoPtr)); /* 485 */
Changes to generic/tclDictObj.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16


















17
18
19
20
21
22
23
/* 
 * tclDictObj.c --
 *
 *	This file contains procedures that implement the Tcl dict object
 *	type and its accessor command.
 *
 * Copyright (c) 2002 by 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: tclDictObj.c,v 1.10.2.1 2003/09/05 23:08:06 dgp Exp $
 */

#include "tclInt.h"



















/*
 * Prototypes for procedures defined later in this file:
 */

static int		DictAppendCmd _ANSI_ARGS_((Tcl_Interp *interp,
			    int objc, Tcl_Obj *CONST *objv));
static int		DictCreateCmd _ANSI_ARGS_((Tcl_Interp *interp,











|




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







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
/* 
 * tclDictObj.c --
 *
 *	This file contains procedures that implement the Tcl dict object
 *	type and its accessor command.
 *
 * Copyright (c) 2002 by 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: tclDictObj.c,v 1.10.2.2 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"

/*
 * Flag values for TraceDictPath().
 *
 * DICT_PATH_UPDATE indicates that we are going to be doing an update
 * at the tip of the path, so duplication of shared objects should be
 * done along the way.
 *
 * DICT_PATH_EXISTS indicates that we are performing an existance test
 * and a lookup failure should therefore not be an error.  If (and
 * only if) this flag is set, TraceDictPath() will return the special
 * value DICT_PATH_NON_EXISTENT if the path is not traceable.
 */

#define DICT_PATH_UPDATE 1
#define DICT_PATH_EXISTS 2

#define DICT_PATH_NON_EXISTENT ((Tcl_Obj *) (void *) 1)

/*
 * Prototypes for procedures defined later in this file:
 */

static int		DictAppendCmd _ANSI_ARGS_((Tcl_Interp *interp,
			    int objc, Tcl_Obj *CONST *objv));
static int		DictCreateCmd _ANSI_ARGS_((Tcl_Interp *interp,
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
			    Tcl_Obj *copyPtr));
static void		FreeDictInternalRep _ANSI_ARGS_((Tcl_Obj *dictPtr));
static int		SetDictFromAny _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *objPtr));
static void		UpdateStringOfDict _ANSI_ARGS_((Tcl_Obj *dictPtr));
static Tcl_Obj *	TraceDictPath _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *rootPtr, int keyc, Tcl_Obj *CONST keyv[],
			    int willUpdate));
struct Dict;
static void		DeleteDict _ANSI_ARGS_((struct Dict *dict));

/*
 * Internal representation of a dictionary.
 *
 * The internal representation of a dictionary object is a hash table







|







72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
			    Tcl_Obj *copyPtr));
static void		FreeDictInternalRep _ANSI_ARGS_((Tcl_Obj *dictPtr));
static int		SetDictFromAny _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *objPtr));
static void		UpdateStringOfDict _ANSI_ARGS_((Tcl_Obj *dictPtr));
static Tcl_Obj *	TraceDictPath _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *rootPtr, int keyc, Tcl_Obj *CONST keyv[],
			    int flags));
struct Dict;
static void		DeleteDict _ANSI_ARGS_((struct Dict *dict));

/*
 * Internal representation of a dictionary.
 *
 * The internal representation of a dictionary object is a hash table
367
368
369
370
371
372
373









374
375
376
377
378
379
380
	if (objc & 1) {
	    if (interp != NULL) {
		Tcl_SetObjResult(interp,
			Tcl_NewStringObj("missing value to go with key", -1));
	    }
	    return TCL_ERROR;
	}










	/*
	 * Build the hash of key/value pairs.
	 */
	dict = (Dict *) ckalloc(sizeof(Dict));
	Tcl_InitObjHashTable(&dict->table);
	for (i=0 ; i<objc ; i+=2) {







>
>
>
>
>
>
>
>
>







385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
	if (objc & 1) {
	    if (interp != NULL) {
		Tcl_SetObjResult(interp,
			Tcl_NewStringObj("missing value to go with key", -1));
	    }
	    return TCL_ERROR;
	}

	/*
	 * If the list is shared its string rep must not be lost so it
	 * still is the same list.
	 */

	if (Tcl_IsShared(objPtr)) {
	    (void) Tcl_GetString(objPtr);
	}

	/*
	 * Build the hash of key/value pairs.
	 */
	dict = (Dict *) ckalloc(sizeof(Dict));
	Tcl_InitObjHashTable(&dict->table);
	for (i=0 ; i<objc ; i+=2) {
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
 *	of dictionaries is also built (in the Dict's chain field) and
 *	the chained dictionaries are made into unshared dictionaries (if
 *	they aren't already.)
 *
 * Results:
 *	The object at the end of the path, or NULL if there was an error.
 *	Note that this it is an error for an intermediate dictionary on
 *	the path to not exist.

 *
 * Side effects:
 *	If the willUpdate flag is false, there are no side effects (other
 *	than potential conversion of objects to dictionaries.)  If the

 *	willUpdate flag is true, the following additional side effects
 *	occur.  Shared dictionaries along the path are converted into
 *	unshared objects, and a backward-pointing chain is built using
 *	the chain fields of the dictionaries (for easy invalidation of
 *	string representations.)
 *
 *----------------------------------------------------------------------
 */

static Tcl_Obj *
TraceDictPath(interp, dictPtr, keyc, keyv, willUpdate)
    Tcl_Interp *interp;
    Tcl_Obj *dictPtr, *CONST keyv[];
    int keyc, willUpdate;
{
    Dict *dict, *newDict;
    int i;

    if (dictPtr->typePtr != &tclDictType) {
	if (SetDictFromAny(interp, dictPtr) != TCL_OK) {
	    return NULL;
	}
    }
    dict = (Dict *) dictPtr->internalRep.otherValuePtr;
    if (willUpdate) {
	dict->chain = NULL;
    }

    for (i=0 ; i<keyc ; i++) {
	Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&dict->table, (char *)keyv[i]);
	Tcl_Obj *tmpObj;

	if (hPtr == NULL) {



	    if (interp != NULL) {
		Tcl_ResetResult(interp);
		Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
			"key \"", TclGetString(keyv[i]),
			"\" not known in dictionary", NULL);
	    }
	    return NULL;
	}

	tmpObj = (Tcl_Obj *) Tcl_GetHashValue(hPtr);
	if (tmpObj->typePtr != &tclDictType) {
	    if (SetDictFromAny(interp, tmpObj) != TCL_OK) {
		return NULL;
	    }
	}
	newDict = (Dict *) tmpObj->internalRep.otherValuePtr;
	if (willUpdate) {
	    if (Tcl_IsShared(tmpObj)) {
		Tcl_DecrRefCount(tmpObj);
		tmpObj = Tcl_DuplicateObj(tmpObj);

		Tcl_SetHashValue(hPtr, (ClientData) tmpObj);
		dict->epoch++;
		newDict = (Dict *) tmpObj->internalRep.otherValuePtr;
	    }

	    newDict->chain = dictPtr;
	}







|
>


|
|
>
|
|
|
|
|





|


|










|








>
>
>
















|



>







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
 *	of dictionaries is also built (in the Dict's chain field) and
 *	the chained dictionaries are made into unshared dictionaries (if
 *	they aren't already.)
 *
 * Results:
 *	The object at the end of the path, or NULL if there was an error.
 *	Note that this it is an error for an intermediate dictionary on
 *	the path to not exist.  If the flags argument is DICT_PATH_EXISTS,
 *	a non-existent path gives a DICT_PATH_NON_EXISTENT result.
 *
 * Side effects:
 *	If the flags argument is zero or DICT_PATH_EXISTS, there are
 *	no side effects (other than potential conversion of objects to
 *	dictionaries.)  If the flags argument is DICT_PATH_UPDATE, the
 *	following additional side effects occur.  Shared dictionaries
 *	along the path are converted into unshared objects, and a
 *	backward-pointing chain is built using the chain fields of the
 *	dictionaries (for easy invalidation of string
 *	representations.)
 *
 *----------------------------------------------------------------------
 */

static Tcl_Obj *
TraceDictPath(interp, dictPtr, keyc, keyv, flags)
    Tcl_Interp *interp;
    Tcl_Obj *dictPtr, *CONST keyv[];
    int keyc, flags;
{
    Dict *dict, *newDict;
    int i;

    if (dictPtr->typePtr != &tclDictType) {
	if (SetDictFromAny(interp, dictPtr) != TCL_OK) {
	    return NULL;
	}
    }
    dict = (Dict *) dictPtr->internalRep.otherValuePtr;
    if (flags == DICT_PATH_UPDATE) {
	dict->chain = NULL;
    }

    for (i=0 ; i<keyc ; i++) {
	Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&dict->table, (char *)keyv[i]);
	Tcl_Obj *tmpObj;

	if (hPtr == NULL) {
	    if (flags == DICT_PATH_EXISTS) {
		return DICT_PATH_NON_EXISTENT;
	    }
	    if (interp != NULL) {
		Tcl_ResetResult(interp);
		Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
			"key \"", TclGetString(keyv[i]),
			"\" not known in dictionary", NULL);
	    }
	    return NULL;
	}

	tmpObj = (Tcl_Obj *) Tcl_GetHashValue(hPtr);
	if (tmpObj->typePtr != &tclDictType) {
	    if (SetDictFromAny(interp, tmpObj) != TCL_OK) {
		return NULL;
	    }
	}
	newDict = (Dict *) tmpObj->internalRep.otherValuePtr;
	if (flags == DICT_PATH_UPDATE) {
	    if (Tcl_IsShared(tmpObj)) {
		Tcl_DecrRefCount(tmpObj);
		tmpObj = Tcl_DuplicateObj(tmpObj);
		Tcl_IncrRefCount(tmpObj);
		Tcl_SetHashValue(hPtr, (ClientData) tmpObj);
		dict->epoch++;
		newDict = (Dict *) tmpObj->internalRep.otherValuePtr;
	    }

	    newDict->chain = dictPtr;
	}
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
    Tcl_Obj *dictPtr, *keyPtr, *valuePtr;
{
    Dict *dict;
    Tcl_HashEntry *hPtr;
    int isNew;

    if (Tcl_IsShared(dictPtr)) {
	panic("Tcl_DictObjPut called with shared object");
    }

    if (dictPtr->typePtr != &tclDictType) {
	int result = SetDictFromAny(interp, dictPtr);
	if (result != TCL_OK) {
	    return result;
	}







|







683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
    Tcl_Obj *dictPtr, *keyPtr, *valuePtr;
{
    Dict *dict;
    Tcl_HashEntry *hPtr;
    int isNew;

    if (Tcl_IsShared(dictPtr)) {
	Tcl_Panic("Tcl_DictObjPut called with shared object");
    }

    if (dictPtr->typePtr != &tclDictType) {
	int result = SetDictFromAny(interp, dictPtr);
	if (result != TCL_OK) {
	    return result;
	}
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
    Tcl_Interp *interp;
    Tcl_Obj *dictPtr, *keyPtr;
{
    Dict *dict;
    Tcl_HashEntry *hPtr;

    if (Tcl_IsShared(dictPtr)) {
	panic("Tcl_DictObjRemove called with shared object");
    }

    if (dictPtr->typePtr != &tclDictType) {
	int result = SetDictFromAny(interp, dictPtr);
	if (result != TCL_OK) {
	    return result;
	}







|







781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
    Tcl_Interp *interp;
    Tcl_Obj *dictPtr, *keyPtr;
{
    Dict *dict;
    Tcl_HashEntry *hPtr;

    if (Tcl_IsShared(dictPtr)) {
	Tcl_Panic("Tcl_DictObjRemove called with shared object");
    }

    if (dictPtr->typePtr != &tclDictType) {
	int result = SetDictFromAny(interp, dictPtr);
	if (result != TCL_OK) {
	    return result;
	}
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
    Tcl_HashEntry *hPtr;

    /*
     * Bail out if the dictionary has had any elements added, modified
     * or removed.  This *shouldn't* happen, but...
     */
    if (((Dict *)searchPtr->dictionaryPtr)->epoch != searchPtr->epoch) {
	panic("concurrent dictionary modification and search");
    }

    hPtr = Tcl_NextHashEntry(&searchPtr->search);
    if (hPtr == NULL) {
	Tcl_DictObjDone(searchPtr);
	*donePtr = 1;
	return;







|







958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
    Tcl_HashEntry *hPtr;

    /*
     * Bail out if the dictionary has had any elements added, modified
     * or removed.  This *shouldn't* happen, but...
     */
    if (((Dict *)searchPtr->dictionaryPtr)->epoch != searchPtr->epoch) {
	Tcl_Panic("concurrent dictionary modification and search");
    }

    hPtr = Tcl_NextHashEntry(&searchPtr->search);
    if (hPtr == NULL) {
	Tcl_DictObjDone(searchPtr);
	*donePtr = 1;
	return;
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
    Tcl_Obj *dictPtr, *CONST keyv[], *valuePtr;
{
    Dict *dict;
    Tcl_HashEntry *hPtr;
    int isNew;

    if (Tcl_IsShared(dictPtr)) {
	panic("Tcl_DictObjPutKeyList called with shared object");
    }
    if (keyc < 1) {
	panic("Tcl_DictObjPutKeyList called with empty key list");
    }

    dictPtr = TraceDictPath(interp, dictPtr, keyc-1, keyv, /*willUpdate*/ 1);
    if (dictPtr == NULL) {
	return TCL_ERROR;
    }

    dict = (Dict *) dictPtr->internalRep.otherValuePtr;
    hPtr = Tcl_CreateHashEntry(&dict->table, (char *)keyv[keyc-1], &isNew);
    Tcl_IncrRefCount(valuePtr);







|


|


|







1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
    Tcl_Obj *dictPtr, *CONST keyv[], *valuePtr;
{
    Dict *dict;
    Tcl_HashEntry *hPtr;
    int isNew;

    if (Tcl_IsShared(dictPtr)) {
	Tcl_Panic("Tcl_DictObjPutKeyList called with shared object");
    }
    if (keyc < 1) {
	Tcl_Panic("Tcl_DictObjPutKeyList called with empty key list");
    }

    dictPtr = TraceDictPath(interp, dictPtr, keyc-1, keyv, DICT_PATH_UPDATE);
    if (dictPtr == NULL) {
	return TCL_ERROR;
    }

    dict = (Dict *) dictPtr->internalRep.otherValuePtr;
    hPtr = Tcl_CreateHashEntry(&dict->table, (char *)keyv[keyc-1], &isNew);
    Tcl_IncrRefCount(valuePtr);
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
    int keyc;
    Tcl_Obj *dictPtr, *CONST keyv[];
{
    Dict *dict;
    Tcl_HashEntry *hPtr;

    if (Tcl_IsShared(dictPtr)) {
	panic("Tcl_DictObjRemoveKeyList called with shared object");
    }
    if (keyc < 1) {
	panic("Tcl_DictObjRemoveKeyList called with empty key list");
    }

    dictPtr = TraceDictPath(interp, dictPtr, keyc-1, keyv, /*willUpdate*/ 1);
    if (dictPtr == NULL) {
	return TCL_ERROR;
    }

    dict = (Dict *) dictPtr->internalRep.otherValuePtr;
    hPtr = Tcl_FindHashEntry(&dict->table, (char *)keyv[keyc-1]);
    if (hPtr != NULL) {







|


|


|







1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
    int keyc;
    Tcl_Obj *dictPtr, *CONST keyv[];
{
    Dict *dict;
    Tcl_HashEntry *hPtr;

    if (Tcl_IsShared(dictPtr)) {
	Tcl_Panic("Tcl_DictObjRemoveKeyList called with shared object");
    }
    if (keyc < 1) {
	Tcl_Panic("Tcl_DictObjRemoveKeyList called with empty key list");
    }

    dictPtr = TraceDictPath(interp, dictPtr, keyc-1, keyv, DICT_PATH_UPDATE);
    if (dictPtr == NULL) {
	return TCL_ERROR;
    }

    dict = (Dict *) dictPtr->internalRep.otherValuePtr;
    hPtr = Tcl_FindHashEntry(&dict->table, (char *)keyv[keyc-1]);
    if (hPtr != NULL) {
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
     * Loop through the list of keys, looking up the key at the
     * current index in the current dictionary each time.  Once we've
     * done the lookup, we set the current dictionary to be the value
     * we looked up (in case the value was not the last one and we are
     * going through a chain of searches.)  Note that this loop always
     * executes at least once.
     */
    dictPtr = TraceDictPath(interp, objv[2], objc-4, objv+3, /*willUpdate*/ 0);
    if (dictPtr == NULL) {
	return TCL_ERROR;
    }
    result = Tcl_DictObjGet(interp, dictPtr, objv[objc-1], &valuePtr);
    if (result != TCL_OK) {
	return result;
    }







|







1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
     * Loop through the list of keys, looking up the key at the
     * current index in the current dictionary each time.  Once we've
     * done the lookup, we set the current dictionary to be the value
     * we looked up (in case the value was not the last one and we are
     * going through a chain of searches.)  Note that this loop always
     * executes at least once.
     */
    dictPtr = TraceDictPath(interp, objv[2], objc-4, objv+3, 0);
    if (dictPtr == NULL) {
	return TCL_ERROR;
    }
    result = Tcl_DictObjGet(interp, dictPtr, objv[objc-1], &valuePtr);
    if (result != TCL_OK) {
	return result;
    }
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
DictReplaceCmd(interp, objc, objv)
    Tcl_Interp *interp;
    int objc;
    Tcl_Obj *CONST *objv;
{
    Tcl_Obj *dictPtr;
    int i, result;


    if ((objc < 3) || !(objc & 1)) {
	Tcl_WrongNumArgs(interp, 2, objv, "dictionary ?key value ...?");
	return TCL_ERROR;
    }

    dictPtr = objv[2];
    if (Tcl_IsShared(dictPtr)) {
	dictPtr = Tcl_DuplicateObj(dictPtr);

    }
    for (i=3 ; i<objc ; i+=2) {
	result = Tcl_DictObjPut(interp, dictPtr, objv[i], objv[i+1]);
	if (result != TCL_OK) {



	    return TCL_ERROR;
	}
    }
    Tcl_SetObjResult(interp, dictPtr);
    return TCL_OK;
}








>









>




>
>
>







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
DictReplaceCmd(interp, objc, objv)
    Tcl_Interp *interp;
    int objc;
    Tcl_Obj *CONST *objv;
{
    Tcl_Obj *dictPtr;
    int i, result;
    int allocatedDict = 0;

    if ((objc < 3) || !(objc & 1)) {
	Tcl_WrongNumArgs(interp, 2, objv, "dictionary ?key value ...?");
	return TCL_ERROR;
    }

    dictPtr = objv[2];
    if (Tcl_IsShared(dictPtr)) {
	dictPtr = Tcl_DuplicateObj(dictPtr);
	allocatedDict = 1;
    }
    for (i=3 ; i<objc ; i+=2) {
	result = Tcl_DictObjPut(interp, dictPtr, objv[i], objv[i+1]);
	if (result != TCL_OK) {
	    if (allocatedDict) {
		Tcl_DecrRefCount(dictPtr);
	    }
	    return TCL_ERROR;
	}
    }
    Tcl_SetObjResult(interp, dictPtr);
    return TCL_OK;
}

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
DictRemoveCmd(interp, objc, objv)
    Tcl_Interp *interp;
    int objc;
    Tcl_Obj *CONST *objv;
{
    Tcl_Obj *dictPtr;
    int i, result;


    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 2, objv, "dictionary ?key ...?");
	return TCL_ERROR;
    }

    dictPtr = objv[2];
    if (Tcl_IsShared(dictPtr)) {
	dictPtr = Tcl_DuplicateObj(dictPtr);

    }
    for (i=3 ; i<objc ; i++) {
	result = Tcl_DictObjRemove(interp, dictPtr, objv[i]);
	if (result != TCL_OK) {



	    return TCL_ERROR;
	}
    }
    Tcl_SetObjResult(interp, dictPtr);
    return TCL_OK;
}








>









>




>
>
>







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
DictRemoveCmd(interp, objc, objv)
    Tcl_Interp *interp;
    int objc;
    Tcl_Obj *CONST *objv;
{
    Tcl_Obj *dictPtr;
    int i, result;
    int allocatedDict = 0;

    if (objc < 3) {
	Tcl_WrongNumArgs(interp, 2, objv, "dictionary ?key ...?");
	return TCL_ERROR;
    }

    dictPtr = objv[2];
    if (Tcl_IsShared(dictPtr)) {
	dictPtr = Tcl_DuplicateObj(dictPtr);
	allocatedDict = 1;
    }
    for (i=3 ; i<objc ; i++) {
	result = Tcl_DictObjRemove(interp, dictPtr, objv[i]);
	if (result != TCL_OK) {
	    if (allocatedDict) {
		Tcl_DecrRefCount(dictPtr);
	    }
	    return TCL_ERROR;
	}
    }
    Tcl_SetObjResult(interp, dictPtr);
    return TCL_OK;
}

1594
1595
1596
1597
1598
1599
1600
1601
1602
1603




1604
1605
1606
1607
1608
1609
1610
    int result;

    if (objc < 4) {
	Tcl_WrongNumArgs(interp, 2, objv, "dictionary key ?key ...?");
	return TCL_ERROR;
    }

    dictPtr = TraceDictPath(interp, objv[2], objc-4, objv+3, /*willUpdate*/ 0);
    if (dictPtr == NULL) {
	return TCL_ERROR;




    }
    result = Tcl_DictObjGet(interp, dictPtr, objv[objc-1], &valuePtr);
    if (result != TCL_OK) {
	return result;
    }
    Tcl_SetObjResult(interp, Tcl_NewBooleanObj(valuePtr != NULL));
    return TCL_OK;







|


>
>
>
>







1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
    int result;

    if (objc < 4) {
	Tcl_WrongNumArgs(interp, 2, objv, "dictionary key ?key ...?");
	return TCL_ERROR;
    }

    dictPtr = TraceDictPath(interp, objv[2], objc-4, objv+3, DICT_PATH_EXISTS);
    if (dictPtr == NULL) {
	return TCL_ERROR;
    }
    if (dictPtr == DICT_PATH_NON_EXISTENT) {
	Tcl_SetObjResult(interp, Tcl_NewBooleanObj(0));
	return TCL_OK;
    }
    result = Tcl_DictObjGet(interp, dictPtr, objv[objc-1], &valuePtr);
    if (result != TCL_OK) {
	return result;
    }
    Tcl_SetObjResult(interp, Tcl_NewBooleanObj(valuePtr != NULL));
    return TCL_OK;
1681
1682
1683
1684
1685
1686
1687

1688
1689
1690
1691
1692
1693
1694
    int objc;
    Tcl_Obj *CONST *objv;
{
    Tcl_Obj *dictPtr, *valuePtr, *resultPtr;
    int result, isWide = 0;
    long incrValue = 1;
    Tcl_WideInt wideIncrValue = 0;


    if (objc < 4 || objc > 5) {
	Tcl_WrongNumArgs(interp, 2, objv, "varName key ?increment?");
	return TCL_ERROR;
    }

    if (objc == 5) {







>







1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
    int objc;
    Tcl_Obj *CONST *objv;
{
    Tcl_Obj *dictPtr, *valuePtr, *resultPtr;
    int result, isWide = 0;
    long incrValue = 1;
    Tcl_WideInt wideIncrValue = 0;
    int allocatedDict = 0;

    if (objc < 4 || objc > 5) {
	Tcl_WrongNumArgs(interp, 2, objv, "varName key ?increment?");
	return TCL_ERROR;
    }

    if (objc == 5) {
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
		isWide = 1;
	    }
	}
    }

    dictPtr = Tcl_ObjGetVar2(interp, objv[2], NULL, 0);
    if (dictPtr == NULL) {

	dictPtr = Tcl_NewDictObj();
	if (isWide) {
	    valuePtr = Tcl_NewWideIntObj(wideIncrValue);
	} else {
	    valuePtr = Tcl_NewLongObj(incrValue);
	}
	Tcl_DictObjPut(interp, dictPtr, objv[3], valuePtr);
    } else {
	long lValue;
	Tcl_WideInt wValue;

	if (Tcl_IsShared(dictPtr)) {

	    dictPtr = Tcl_DuplicateObj(dictPtr);
	}

	if (Tcl_DictObjGet(interp, dictPtr, objv[3], &valuePtr) != TCL_OK) {



	    return TCL_ERROR;
	}
	if (valuePtr == NULL) {
	    if (isWide) {
		valuePtr = Tcl_NewWideIntObj(wideIncrValue);
	    } else {
		valuePtr = Tcl_NewLongObj(incrValue);







>












>




>
>
>







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
		isWide = 1;
	    }
	}
    }

    dictPtr = Tcl_ObjGetVar2(interp, objv[2], NULL, 0);
    if (dictPtr == NULL) {
	allocatedDict = 1;
	dictPtr = Tcl_NewDictObj();
	if (isWide) {
	    valuePtr = Tcl_NewWideIntObj(wideIncrValue);
	} else {
	    valuePtr = Tcl_NewLongObj(incrValue);
	}
	Tcl_DictObjPut(interp, dictPtr, objv[3], valuePtr);
    } else {
	long lValue;
	Tcl_WideInt wValue;

	if (Tcl_IsShared(dictPtr)) {
	    allocatedDict = 1;
	    dictPtr = Tcl_DuplicateObj(dictPtr);
	}

	if (Tcl_DictObjGet(interp, dictPtr, objv[3], &valuePtr) != TCL_OK) {
	    if (allocatedDict) {
		Tcl_DecrRefCount(dictPtr);
	    }
	    return TCL_ERROR;
	}
	if (valuePtr == NULL) {
	    if (isWide) {
		valuePtr = Tcl_NewWideIntObj(wideIncrValue);
	    } else {
		valuePtr = Tcl_NewLongObj(incrValue);
1781
1782
1783
1784
1785
1786
1787



1788
1789
1790
1791
1792
1793
1794
	     * Note that these operations on wide ints should work
	     * fine where they are the same as normal longs, though
	     * the compiler might complain about trivially satisifed
	     * tests.
	     */
	    result = Tcl_GetWideIntFromObj(interp, valuePtr, &wValue);
	    if (result != TCL_OK) {



		return result;
	    }
	    /*
	     * Determine if we should have got a standard long instead.
	     */
	    if (Tcl_IsShared(valuePtr)) {
		if (isWide) {







>
>
>







1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
	     * Note that these operations on wide ints should work
	     * fine where they are the same as normal longs, though
	     * the compiler might complain about trivially satisifed
	     * tests.
	     */
	    result = Tcl_GetWideIntFromObj(interp, valuePtr, &wValue);
	    if (result != TCL_OK) {
		if (allocatedDict) {
		    Tcl_DecrRefCount(dictPtr);
		}
		return result;
	    }
	    /*
	     * Determine if we should have got a standard long instead.
	     */
	    if (Tcl_IsShared(valuePtr)) {
		if (isWide) {
1814
1815
1816
1817
1818
1819
1820







1821
1822
1823
1824
1825

1826
1827
1828
1829

1830
1831
1832
1833
1834
1835
1836
		if (dictPtr->bytes != NULL) {
		    Tcl_InvalidateStringRep(dictPtr);
		}
		goto valueAlreadyInDictionary;
	    }
	}
	if (Tcl_DictObjPut(interp, dictPtr, objv[3], valuePtr) != TCL_OK) {







	    Tcl_DecrRefCount(valuePtr);
	    return TCL_ERROR;
	}
    }
  valueAlreadyInDictionary:

    resultPtr = Tcl_ObjSetVar2(interp, objv[2], NULL, dictPtr,
	    TCL_LEAVE_ERR_MSG);
    if (resultPtr == NULL) {
	Tcl_DecrRefCount(dictPtr);

	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, resultPtr);
    return TCL_OK;
}

/*







>
>
>
>
>
>
>





>


<
|
>







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
		if (dictPtr->bytes != NULL) {
		    Tcl_InvalidateStringRep(dictPtr);
		}
		goto valueAlreadyInDictionary;
	    }
	}
	if (Tcl_DictObjPut(interp, dictPtr, objv[3], valuePtr) != TCL_OK) {
	    /* 
	     * This shouldn't happen since dictPtr is known
	     * from above to be a valid dictionary.
	     */
	    if (allocatedDict) {
		Tcl_DecrRefCount(dictPtr);
	    }
	    Tcl_DecrRefCount(valuePtr);
	    return TCL_ERROR;
	}
    }
  valueAlreadyInDictionary:
    Tcl_IncrRefCount(dictPtr);
    resultPtr = Tcl_ObjSetVar2(interp, objv[2], NULL, dictPtr,
	    TCL_LEAVE_ERR_MSG);

    Tcl_DecrRefCount(dictPtr);
    if (resultPtr == NULL) {
	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, resultPtr);
    return TCL_OK;
}

/*
1906
1907
1908
1909
1910
1911
1912

1913
1914
1915
1916
1917
1918

1919
1920
1921
1922
1923
1924
1925

    if (allocatedValue) {
	Tcl_DictObjPut(interp, dictPtr, objv[3], valuePtr);
    } else if (dictPtr->bytes != NULL) {
	Tcl_InvalidateStringRep(dictPtr);
    }


    resultPtr = Tcl_ObjSetVar2(interp, objv[2], NULL, dictPtr,
	    TCL_LEAVE_ERR_MSG);
    if (resultPtr == NULL) {
	if (allocatedDict) {
	    Tcl_DecrRefCount(dictPtr);
	}

	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, resultPtr);
    return TCL_OK;
}

/*







>


<
<
|
<
>







1970
1971
1972
1973
1974
1975
1976
1977
1978
1979


1980

1981
1982
1983
1984
1985
1986
1987
1988

    if (allocatedValue) {
	Tcl_DictObjPut(interp, dictPtr, objv[3], valuePtr);
    } else if (dictPtr->bytes != NULL) {
	Tcl_InvalidateStringRep(dictPtr);
    }

    Tcl_IncrRefCount(dictPtr);
    resultPtr = Tcl_ObjSetVar2(interp, objv[2], NULL, dictPtr,
	    TCL_LEAVE_ERR_MSG);


    Tcl_DecrRefCount(dictPtr);

    if (resultPtr == NULL) {
	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, resultPtr);
    return TCL_OK;
}

/*
1980
1981
1982
1983
1984
1985
1986

1987
1988
1989
1990
1991
1992

1993
1994
1995
1996
1997
1998
1999

    for (i=4 ; i<objc ; i++) {
	Tcl_AppendObjToObj(valuePtr, objv[i]);
    }

    Tcl_DictObjPut(interp, dictPtr, objv[3], valuePtr);


    resultPtr = Tcl_ObjSetVar2(interp, objv[2], NULL, dictPtr,
	    TCL_LEAVE_ERR_MSG);
    if (resultPtr == NULL) {
	if (allocatedDict) {
	    Tcl_DecrRefCount(dictPtr);
	}

	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, resultPtr);
    return TCL_OK;
}

/*







>


<
<
|
<
>







2043
2044
2045
2046
2047
2048
2049
2050
2051
2052


2053

2054
2055
2056
2057
2058
2059
2060
2061

    for (i=4 ; i<objc ; i++) {
	Tcl_AppendObjToObj(valuePtr, objv[i]);
    }

    Tcl_DictObjPut(interp, dictPtr, objv[3], valuePtr);

    Tcl_IncrRefCount(dictPtr);
    resultPtr = Tcl_ObjSetVar2(interp, objv[2], NULL, dictPtr,
	    TCL_LEAVE_ERR_MSG);


    Tcl_DecrRefCount(dictPtr);

    if (resultPtr == NULL) {
	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, resultPtr);
    return TCL_OK;
}

/*
2184
2185
2186
2187
2188
2189
2190

2191
2192
2193
2194
2195
2196

2197
2198
2199
2200
2201
2202
2203
    if (result != TCL_OK) {
	if (allocatedDict) {
	    Tcl_DecrRefCount(dictPtr);
	}
	return TCL_ERROR;
    }


    resultPtr = Tcl_ObjSetVar2(interp, objv[2], NULL, dictPtr,
	    TCL_LEAVE_ERR_MSG);
    if (resultPtr == NULL) {
	if (allocatedDict) {
	    Tcl_DecrRefCount(dictPtr);
	}

	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, resultPtr);
    return TCL_OK;
}

/*







>


<
<
|
<
>







2246
2247
2248
2249
2250
2251
2252
2253
2254
2255


2256

2257
2258
2259
2260
2261
2262
2263
2264
    if (result != TCL_OK) {
	if (allocatedDict) {
	    Tcl_DecrRefCount(dictPtr);
	}
	return TCL_ERROR;
    }

    Tcl_IncrRefCount(dictPtr);
    resultPtr = Tcl_ObjSetVar2(interp, objv[2], NULL, dictPtr,
	    TCL_LEAVE_ERR_MSG);


    Tcl_DecrRefCount(dictPtr);

    if (resultPtr == NULL) {
	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, resultPtr);
    return TCL_OK;
}

/*
2245
2246
2247
2248
2249
2250
2251

2252
2253
2254
2255
2256
2257

2258
2259
2260
2261
2262
2263
2264
    if (result != TCL_OK) {
	if (allocatedDict) {
	    Tcl_DecrRefCount(dictPtr);
	}
	return TCL_ERROR;
    }


    resultPtr = Tcl_ObjSetVar2(interp, objv[2], NULL, dictPtr,
	    TCL_LEAVE_ERR_MSG);
    if (resultPtr == NULL) {
	if (allocatedDict) {
	    Tcl_DecrRefCount(dictPtr);
	}

	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, resultPtr);
    return TCL_OK;
}

/*







>


<
<
|
<
>







2306
2307
2308
2309
2310
2311
2312
2313
2314
2315


2316

2317
2318
2319
2320
2321
2322
2323
2324
    if (result != TCL_OK) {
	if (allocatedDict) {
	    Tcl_DecrRefCount(dictPtr);
	}
	return TCL_ERROR;
    }

    Tcl_IncrRefCount(dictPtr);
    resultPtr = Tcl_ObjSetVar2(interp, objv[2], NULL, dictPtr,
	    TCL_LEAVE_ERR_MSG);


    Tcl_DecrRefCount(dictPtr);

    if (resultPtr == NULL) {
	return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, resultPtr);
    return TCL_OK;
}

/*
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
	if (result == TCL_OK) {
	    Tcl_SetObjResult(interp, resultObj);
	} else {
	    Tcl_DecrRefCount(resultObj);
	}
	return result;
    }
    panic("unexpected fallthrough");
    /* Control never reaches this point. */
    return TCL_ERROR;

  abnormalResult:
    Tcl_DictObjDone(&search);
    Tcl_DecrRefCount(keyObj);
    Tcl_DecrRefCount(valueObj);







|







2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
	if (result == TCL_OK) {
	    Tcl_SetObjResult(interp, resultObj);
	} else {
	    Tcl_DecrRefCount(resultObj);
	}
	return result;
    }
    Tcl_Panic("unexpected fallthrough");
    /* Control never reaches this point. */
    return TCL_ERROR;

  abnormalResult:
    Tcl_DictObjDone(&search);
    Tcl_DecrRefCount(keyObj);
    Tcl_DecrRefCount(valueObj);
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
    case DICT_REMOVE:	return DictRemoveCmd(interp, objc, objv);
    case DICT_REPLACE:	return DictReplaceCmd(interp, objc, objv);
    case DICT_SET:	return DictSetCmd(interp, objc, objv);
    case DICT_SIZE:	return DictSizeCmd(interp, objc, objv);
    case DICT_UNSET:	return DictUnsetCmd(interp, objc, objv);
    case DICT_VALUES:	return DictValuesCmd(interp, objc, objv);
    }
    panic("unexpected fallthrough!");
    /*
     * Next line is NOT REACHED - stops compliler complaint though...
     */
    return TCL_ERROR;
}







|





2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
    case DICT_REMOVE:	return DictRemoveCmd(interp, objc, objv);
    case DICT_REPLACE:	return DictReplaceCmd(interp, objc, objv);
    case DICT_SET:	return DictSetCmd(interp, objc, objv);
    case DICT_SIZE:	return DictSizeCmd(interp, objc, objv);
    case DICT_UNSET:	return DictUnsetCmd(interp, objc, objv);
    case DICT_VALUES:	return DictValuesCmd(interp, objc, objv);
    }
    Tcl_Panic("unexpected fallthrough!");
    /*
     * Next line is NOT REACHED - stops compliler complaint though...
     */
    return TCL_ERROR;
}
Changes to generic/tclEncoding.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
 * tclEncoding.c --
 *
 *	Contains the implementation of the encoding conversion package.
 *
 * Copyright (c) 1996-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.
 *
 * RCS: @(#) $Id: tclEncoding.c,v 1.16 2003/02/21 02:40:58 hobbs Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

typedef size_t (LengthProc)_ANSI_ARGS_((CONST char *src));











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
 * tclEncoding.c --
 *
 *	Contains the implementation of the encoding conversion package.
 *
 * Copyright (c) 1996-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.
 *
 * RCS: @(#) $Id: tclEncoding.c,v 1.16.4.1 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

typedef size_t (LengthProc)_ANSI_ARGS_((CONST char *src));

2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
    
    subTablePtr = &dataPtr->subTables[state];
    encodingPtr = subTablePtr->encodingPtr;
    if (encodingPtr == NULL) {
	encodingPtr = (Encoding *) Tcl_GetEncoding(NULL, subTablePtr->name);
	if ((encodingPtr == NULL) 
		|| (encodingPtr->toUtfProc != TableToUtfProc)) {
	    panic("EscapeToUtfProc: invalid sub table");
	}
	subTablePtr->encodingPtr = encodingPtr;
    }
    return encodingPtr;
}

/*







|







2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
    
    subTablePtr = &dataPtr->subTables[state];
    encodingPtr = subTablePtr->encodingPtr;
    if (encodingPtr == NULL) {
	encodingPtr = (Encoding *) Tcl_GetEncoding(NULL, subTablePtr->name);
	if ((encodingPtr == NULL) 
		|| (encodingPtr->toUtfProc != TableToUtfProc)) {
	    Tcl_Panic("EscapeToUtfProc: invalid sub table");
	}
	subTablePtr->encodingPtr = encodingPtr;
    }
    return encodingPtr;
}

/*
Changes to generic/tclEvent.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclEvent.c --
 *
 *	This file implements some general event related interfaces including
 *	background errors, exit handlers, and the "vwait" and "update"
 *	command procedures. 
 *
 * Copyright (c) 1990-1994 The Regents of the University of California.
 * Copyright (c) 1994-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.
 *
 * RCS: @(#) $Id: tclEvent.c,v 1.29.2.1 2003/10/16 02:28:02 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * The data structure below is used to report background errors.  One













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclEvent.c --
 *
 *	This file implements some general event related interfaces including
 *	background errors, exit handlers, and the "vwait" and "update"
 *	command procedures. 
 *
 * Copyright (c) 1990-1994 The Regents of the University of California.
 * Copyright (c) 1994-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.
 *
 * RCS: @(#) $Id: tclEvent.c,v 1.29.2.2 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * The data structure below is used to report background errors.  One
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
    currentAppExitPtr = appExitPtr;
    Tcl_MutexUnlock(&exitMutex);

    if (currentAppExitPtr) {
	/*
	 * Warning: this code SHOULD NOT return, as there is code that
	 * depends on Tcl_Exit never returning.  In fact, we will
	 * panic if anyone returns, so critical is this dependcy.
	 */
	currentAppExitPtr((ClientData) status);
	Tcl_Panic("AppExitProc returned unexpectedly");
    } else {
	/* use default handling */
	Tcl_Finalize();
	TclpExit(status);







|







613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
    currentAppExitPtr = appExitPtr;
    Tcl_MutexUnlock(&exitMutex);

    if (currentAppExitPtr) {
	/*
	 * Warning: this code SHOULD NOT return, as there is code that
	 * depends on Tcl_Exit never returning.  In fact, we will
	 * Tcl_Panic if anyone returns, so critical is this dependcy.
	 */
	currentAppExitPtr((ClientData) status);
	Tcl_Panic("AppExitProc returned unexpectedly");
    } else {
	/* use default handling */
	Tcl_Finalize();
	TclpExit(status);
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
TclInitSubsystems(argv0)
    CONST char *argv0;		/* Name of executable from argv[0] to main()
				 * in native multi-byte encoding. */
{
    ThreadSpecificData *tsdPtr;

    if (inFinalize != 0) {
	panic("TclInitSubsystems called while finalizing");
    }

    /*
     * Grab the thread local storage pointer before doing anything because
     * the initialization routines will be registering exit handlers.
     * We use this pointer to detect if this is the first time this
     * thread has created an interpreter.







|







738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
TclInitSubsystems(argv0)
    CONST char *argv0;		/* Name of executable from argv[0] to main()
				 * in native multi-byte encoding. */
{
    ThreadSpecificData *tsdPtr;

    if (inFinalize != 0) {
	Tcl_Panic("TclInitSubsystems called while finalizing");
    }

    /*
     * Grab the thread local storage pointer before doing anything because
     * the initialization routines will be registering exit handlers.
     * We use this pointer to detect if this is the first time this
     * thread has created an interpreter.
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
	}
	switch ((enum updateOptions) optionIndex) {
	    case REGEXP_IDLETASKS: {
		flags = TCL_WINDOW_EVENTS|TCL_IDLE_EVENTS|TCL_DONT_WAIT;
		break;
	    }
	    default: {
		panic("Tcl_UpdateObjCmd: bad option index to UpdateOptions");
	    }
	}
    } else {
        Tcl_WrongNumArgs(interp, 1, objv, "?idletasks?");
	return TCL_ERROR;
    }
    







|







1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
	}
	switch ((enum updateOptions) optionIndex) {
	    case REGEXP_IDLETASKS: {
		flags = TCL_WINDOW_EVENTS|TCL_IDLE_EVENTS|TCL_DONT_WAIT;
		break;
	    }
	    default: {
		Tcl_Panic("Tcl_UpdateObjCmd: bad option index to UpdateOptions");
	    }
	}
    } else {
        Tcl_WrongNumArgs(interp, 1, objv, "?idletasks?");
	return TCL_ERROR;
    }
    
Changes to generic/tclExecute.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclExecute.c --
 *
 *	This file contains procedures that execute byte-compiled Tcl
 *	commands.
 *
 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 by Scriptics Corporation.
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclExecute.c,v 1.101.2.5 2003/10/16 02:28:02 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"

#ifndef TCL_NO_MATH
#   include "tclMath.h"













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclExecute.c --
 *
 *	This file contains procedures that execute byte-compiled Tcl
 *	commands.
 *
 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 by Scriptics Corporation.
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclExecute.c,v 1.101.2.6 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"

#ifndef TCL_NO_MATH
#   include "tclMath.h"
57
58
59
60
61
62
63










64
65
66
67
68
69
70
 * This value is from the Solaris headers, but doubles seem to be the
 * same size everywhere.  Long doubles aren't, but we don't use those.
 */
#	define DBL_MAX 1.79769313486231570e+308
#   endif /* MAXDOUBLE */
#endif /* !DBL_MAX */











/*
 * Boolean flag indicating whether the Tcl bytecode interpreter has been
 * initialized.
 */

static int execInitialized = 0;
TCL_DECLARE_MUTEX(execMutex)







>
>
>
>
>
>
>
>
>
>







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
 * This value is from the Solaris headers, but doubles seem to be the
 * same size everywhere.  Long doubles aren't, but we don't use those.
 */
#	define DBL_MAX 1.79769313486231570e+308
#   endif /* MAXDOUBLE */
#endif /* !DBL_MAX */

/*
 * A mask (should be 2**n-1) that is used to work out when the
 * bytecode engine should call Tcl_AsyncReady() to see whether there
 * is a signal that needs handling.
 */

#ifndef ASYNC_CHECK_COUNT_MASK
#   define ASYNC_CHECK_COUNT_MASK	15
#endif /* !ASYNC_CHECK_COUNT_MASK */

/*
 * Boolean flag indicating whether the Tcl bytecode interpreter has been
 * initialized.
 */

static int execInitialized = 0;
TCL_DECLARE_MUTEX(execMutex)
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
 * at compile time. (result) is always a constant; the macro 
 * NEXT_INST_F handles constant (nCleanup), NEXT_INST_V is
 * resolved at runtime for variable (nCleanup).
 *
 * ARGUMENTS:
 *    pcAdjustment: how much to increment pc
 *    nCleanup: how many objects to remove from the stack
 *    result: 0 indicates no object should be pushed on the
 *       stack; otherwise, push objResultPtr. If (result < 0),
 *       objResultPtr already has the correct reference count.
 */

#define NEXT_INST_F(pcAdjustment, nCleanup, result) \
     if (nCleanup == 0) {\
	 if (result != 0) {\
	     if ((result) > 0) {\
		 PUSH_OBJECT(objResultPtr);\
	     } else {\
		 *(++tosPtr) = objResultPtr;\
	     }\
	 } \
	 pc += (pcAdjustment);\
	 goto cleanup0;\
     } else if (result != 0) {\
	 if ((result) > 0) {\
	     Tcl_IncrRefCount(objResultPtr);\
	 }\
	 pc += (pcAdjustment);\
	 switch (nCleanup) {\
	     case 1: goto cleanup1_pushObjResultPtr;\
	     case 2: goto cleanup2_pushObjResultPtr;\
	     default: panic("ERROR: bad usage of macro NEXT_INST_F");\
	 }\
     } else {\
	 pc += (pcAdjustment);\
	 switch (nCleanup) {\
	     case 1: goto cleanup1;\
	     case 2: goto cleanup2;\
	     default: panic("ERROR: bad usage of macro NEXT_INST_F");\
	 }\
     }

#define NEXT_INST_V(pcAdjustment, nCleanup, result) \
    pc += (pcAdjustment);\
    cleanup = (nCleanup);\
    if (result) {\
	if ((result) > 0) {\
	    Tcl_IncrRefCount(objResultPtr);\
	}\
	goto cleanupV_pushObjResultPtr;\
    } else {\
	goto cleanupV;\
    }








|




|

|
|







|
|






|






|



|


|
|







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
 * at compile time. (result) is always a constant; the macro 
 * NEXT_INST_F handles constant (nCleanup), NEXT_INST_V is
 * resolved at runtime for variable (nCleanup).
 *
 * ARGUMENTS:
 *    pcAdjustment: how much to increment pc
 *    nCleanup: how many objects to remove from the stack
 *    resultHandling: 0 indicates no object should be pushed on the
 *       stack; otherwise, push objResultPtr. If (result < 0),
 *       objResultPtr already has the correct reference count.
 */

#define NEXT_INST_F(pcAdjustment, nCleanup, resultHandling) \
     if (nCleanup == 0) {\
	 if (resultHandling != 0) {\
	     if ((resultHandling) > 0) {\
		 PUSH_OBJECT(objResultPtr);\
	     } else {\
		 *(++tosPtr) = objResultPtr;\
	     }\
	 } \
	 pc += (pcAdjustment);\
	 goto cleanup0;\
     } else if (resultHandling != 0) {\
	 if ((resultHandling) > 0) {\
	     Tcl_IncrRefCount(objResultPtr);\
	 }\
	 pc += (pcAdjustment);\
	 switch (nCleanup) {\
	     case 1: goto cleanup1_pushObjResultPtr;\
	     case 2: goto cleanup2_pushObjResultPtr;\
	     default: Tcl_Panic("ERROR: bad usage of macro NEXT_INST_F");\
	 }\
     } else {\
	 pc += (pcAdjustment);\
	 switch (nCleanup) {\
	     case 1: goto cleanup1;\
	     case 2: goto cleanup2;\
	     default: Tcl_Panic("ERROR: bad usage of macro NEXT_INST_F");\
	 }\
     }

#define NEXT_INST_V(pcAdjustment, nCleanup, resultHandling) \
    pc += (pcAdjustment);\
    cleanup = (nCleanup);\
    if (resultHandling) {\
	if ((resultHandling) > 0) {\
	    Tcl_IncrRefCount(objResultPtr);\
	}\
	goto cleanupV_pushObjResultPtr;\
    } else {\
	goto cleanupV;\
    }

451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
    Tcl_Interp *interp;		/* Interpreter for which the Tcl variable
				 * "tcl_traceExec" is linked to control
				 * instruction tracing. */
{
#ifdef TCL_COMPILE_DEBUG
    if (Tcl_LinkVar(interp, "tcl_traceExec", (char *) &tclTraceExec,
		    TCL_LINK_INT) != TCL_OK) {
	panic("InitByteCodeExecution: can't create link for tcl_traceExec variable");
    }
#endif
#ifdef TCL_COMPILE_STATS    
    Tcl_CreateObjCommand(interp, "evalstats", EvalStatsCmd,
	    (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
#endif /* TCL_COMPILE_STATS */
}







|







461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
    Tcl_Interp *interp;		/* Interpreter for which the Tcl variable
				 * "tcl_traceExec" is linked to control
				 * instruction tracing. */
{
#ifdef TCL_COMPILE_DEBUG
    if (Tcl_LinkVar(interp, "tcl_traceExec", (char *) &tclTraceExec,
		    TCL_LINK_INT) != TCL_OK) {
	Tcl_Panic("InitByteCodeExecution: can't create link for tcl_traceExec variable");
    }
#endif
#ifdef TCL_COMPILE_STATS    
    Tcl_CreateObjCommand(interp, "evalstats", EvalStatsCmd,
	    (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL);
#endif /* TCL_COMPILE_STATS */
}
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
void
TclDeleteExecEnv(eePtr)
    ExecEnv *eePtr;		/* Execution environment to free. */
{
    if (eePtr->stackPtr[-1] == (Tcl_Obj *) ((char *) 1)) {
	ckfree((char *) (eePtr->stackPtr-1));
    } else {
	panic("ERROR: freeing an execEnv whose stack is still in use.\n");
    }
    TclDecrRefCount(eePtr->errorInfo);
    TclDecrRefCount(eePtr->errorCode);
    ckfree((char *) eePtr);
}

/*







|







559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
void
TclDeleteExecEnv(eePtr)
    ExecEnv *eePtr;		/* Execution environment to free. */
{
    if (eePtr->stackPtr[-1] == (Tcl_Obj *) ((char *) 1)) {
	ckfree((char *) (eePtr->stackPtr-1));
    } else {
	Tcl_Panic("ERROR: freeing an execEnv whose stack is still in use.\n");
    }
    TclDecrRefCount(eePtr->errorInfo);
    TclDecrRefCount(eePtr->errorCode);
    ckfree((char *) eePtr);
}

/*
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756

    if (objPtr->typePtr == &tclByteCodeType) {
	codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
	if (((Interp *) *codePtr->interpHandle != iPtr)
	        || (codePtr->compileEpoch != iPtr->compileEpoch)) {
            if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
                if ((Interp *) *codePtr->interpHandle != iPtr) {
                    panic("Tcl_ExprObj: compiled expression jumped interps");
                }
	        codePtr->compileEpoch = iPtr->compileEpoch;
            } else {
                (*tclByteCodeType.freeIntRepProc)(objPtr);
                objPtr->typePtr = (Tcl_ObjType *) NULL;
            }
	}







|







752
753
754
755
756
757
758
759
760
761
762
763
764
765
766

    if (objPtr->typePtr == &tclByteCodeType) {
	codePtr = (ByteCode *) objPtr->internalRep.otherValuePtr;
	if (((Interp *) *codePtr->interpHandle != iPtr)
	        || (codePtr->compileEpoch != iPtr->compileEpoch)) {
            if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
                if ((Interp *) *codePtr->interpHandle != iPtr) {
                    Tcl_Panic("Tcl_ExprObj: compiled expression jumped interps");
                }
	        codePtr->compileEpoch = iPtr->compileEpoch;
            } else {
                (*tclByteCodeType.freeIntRepProc)(objPtr);
                objPtr->typePtr = (Tcl_ObjType *) NULL;
            }
	}
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
		|| (codePtr->procPtr != NULL && !(iPtr->varFramePtr &&
			iPtr->varFramePtr->procPtr == codePtr->procPtr))
#endif
	        || (codePtr->nsPtr != namespacePtr)
	        || (codePtr->nsEpoch != namespacePtr->resolverEpoch)) {
            if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
                if ((Interp *) *codePtr->interpHandle != iPtr) {
                    panic("Tcl_EvalObj: compiled script jumped interps");
                }
	        codePtr->compileEpoch = iPtr->compileEpoch;
            } else {
		/*
		 * This byteCode is invalid: free it and recompile
		 */
                tclByteCodeType.freeIntRepProc(objPtr);







|







968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
		|| (codePtr->procPtr != NULL && !(iPtr->varFramePtr &&
			iPtr->varFramePtr->procPtr == codePtr->procPtr))
#endif
	        || (codePtr->nsPtr != namespacePtr)
	        || (codePtr->nsEpoch != namespacePtr->resolverEpoch)) {
            if (codePtr->flags & TCL_BYTECODE_PRECOMPILED) {
                if ((Interp *) *codePtr->interpHandle != iPtr) {
                    Tcl_Panic("Tcl_EvalObj: compiled script jumped interps");
                }
	        codePtr->compileEpoch = iPtr->compileEpoch;
            } else {
		/*
		 * This byteCode is invalid: free it and recompile
		 */
                tclByteCodeType.freeIntRepProc(objPtr);
1079
1080
1081
1082
1083
1084
1085

1086

1087
1088
1089
1090
1091
1092
1093


1094
1095
1096
1097
1098
1099
1100
    Tcl_Obj *valuePtr, *value2Ptr, *objPtr;
    char *bytes;
    int length;
    long i = 0;			/* Init. avoids compiler warning. */
    Tcl_WideInt w;
    int isWide;
    register int cleanup;

    Tcl_Obj *objResultPtr;

    char *part1, *part2;
    Var *varPtr, *arrayPtr;
    CallFrame *varFramePtr = iPtr->varFramePtr;
#ifdef TCL_COMPILE_DEBUG
    int traceInstructions = (tclTraceExec == 3);
    char cmdNameBuf[21];
#endif



    /*
     * The execution uses a unified stack: first the catch stack, immediately
     * above it the execution stack.
     *
     * Make sure the catch stack is large enough to hold the maximum number
     * of catch commands that could ever be executing at the same time (this







>

>







>
>







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
    Tcl_Obj *valuePtr, *value2Ptr, *objPtr;
    char *bytes;
    int length;
    long i = 0;			/* Init. avoids compiler warning. */
    Tcl_WideInt w;
    int isWide;
    register int cleanup;
    int objc = 0;
    Tcl_Obj *objResultPtr;
    Tcl_Obj **objv = NULL, **stackObjArray = NULL;
    char *part1, *part2;
    Var *varPtr, *arrayPtr;
    CallFrame *varFramePtr = iPtr->varFramePtr;
#ifdef TCL_COMPILE_DEBUG
    int traceInstructions = (tclTraceExec == 3);
    char cmdNameBuf[21];
#endif
    int instructionCount = 0;	/* Counter that is used to work out
				 * when to call Tcl_AsyncReady() */

    /*
     * The execution uses a unified stack: first the catch stack, immediately
     * above it the execution stack.
     *
     * Make sure the catch stack is large enough to hold the maximum number
     * of catch commands that could ever be executing at the same time (this
1201
1202
1203
1204
1205
1206
1207















1208
1209




1210




1211


1212
1213
1214


1215
1216
1217
1218
1219
1220
1221
1222
	fflush(stdout);
    }
#endif /* TCL_COMPILE_DEBUG */
    
#ifdef TCL_COMPILE_STATS    
    iPtr->stats.instructionCount[*pc]++;
#endif















    switch (*pc) {
    case INST_RETURN:




	if (iPtr->returnOpts != iPtr->defaultReturnOpts) {




	    Tcl_DecrRefCount(iPtr->returnOpts);


	    iPtr->returnOpts = iPtr->defaultReturnOpts;
	    Tcl_IncrRefCount(iPtr->returnOpts);
	}


	result = TCL_RETURN;
    case INST_DONE:
	if (tosPtr <= eePtr->stackPtr + initStackTop) {
	    tosPtr--;
	    goto abnormalReturn;
	}
	
	/*







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


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







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
	fflush(stdout);
    }
#endif /* TCL_COMPILE_DEBUG */
    
#ifdef TCL_COMPILE_STATS    
    iPtr->stats.instructionCount[*pc]++;
#endif

    /*
     * Check for asynchronous handlers [Bug 746722]; we
     * do the check every 16th instruction.
     */

    if (!(instructionCount++ & ASYNC_CHECK_COUNT_MASK) && Tcl_AsyncReady()) {
	DECACHE_STACK_INFO();
	result = Tcl_AsyncInvoke(interp, result);
	CACHE_STACK_INFO();
	if (result == TCL_ERROR) {
	    goto checkForCatch;
	}
    }

    switch (*pc) {
    case INST_RETURN:
	{
	    int code = TclGetInt4AtPtr(pc+1);
	    int level = TclGetUInt4AtPtr(pc+5);
	    Tcl_Obj *returnOpts = POP_OBJECT();

	    DECACHE_STACK_INFO();
	    Tcl_ResetResult(interp);
	    result = TclProcessReturn(interp, code, level, returnOpts);
	    CACHE_STACK_INFO();
	    Tcl_DecrRefCount(returnOpts);
	    if (result != TCL_OK) {
		Tcl_SetObjResult(interp, *tosPtr);
		cleanup = 1;
		goto processExceptionReturn;
	    }
	    NEXT_INST_F(9, 0, 0);
	}

    case INST_DONE:
	if (tosPtr <= eePtr->stackPtr + initStackTop) {
	    tosPtr--;
	    goto abnormalReturn;
	}
	
	/*
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
		}
		*p = '\0';
	    }
		
	    TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
	    NEXT_INST_V(2, opnd, 1);
	}
	    



































































































    case INST_INVOKE_STK4:
	opnd = TclGetUInt4AtPtr(pc+1);


	pcAdjustment = 5;
	goto doInvocation;

    case INST_INVOKE_STK1:
	opnd = TclGetUInt1AtPtr(pc+1);


	pcAdjustment = 2;
	    
    doInvocation:
	{
	    int objc = opnd; /* The number of arguments. */
	    Tcl_Obj **objv;	 /* The array of argument objects. */

	    /*
	     * We keep the stack reference count as a (char *), as that
	     * works nicely as a portable pointer-sized counter.
	     */

	    char **preservedStackRefCountPtr;
	    
	    /* 
	     * Reference to memory block containing
	     * objv array (must be kept live throughout
	     * trace and command invokations.) 
	     */

	    objv = (tosPtr - (objc-1));

#ifdef TCL_COMPILE_DEBUG
	    if (tclTraceExec >= 2) {
		if (traceInstructions) {
		    strncpy(cmdNameBuf, TclGetString(objv[0]), 20);
		    TRACE(("%u => call ", objc));
		} else {
		    fprintf(stdout, "%d: (%u) invoking ",







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


>
>





>
>




<
<
<







<
<
<
<
<
<
<
<







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
		}
		*p = '\0';
	    }
		
	    TRACE_WITH_OBJ(("%u => ", opnd), objResultPtr);
	    NEXT_INST_V(2, opnd, 1);
	}

    case INST_LIST_VERIFY:
	{  
	    int numElements = 0;
	    valuePtr = *tosPtr;

	    result = Tcl_ListObjLength(interp, valuePtr, &numElements);
	    if (result != TCL_OK) {
		TRACE_WITH_OBJ(("%.30s => ERROR: ", O2S(valuePtr)),
	        	Tcl_GetObjResult(interp));
		goto checkForCatch;
	    }
	    NEXT_INST_F(1, 0, 0);
	}

    case INST_INVOKE_EXP:
	{
	    int numWords = TclGetUInt4AtPtr(pc+1);
	    int spaceAvailable = eePtr->endPtr - tosPtr;
	    unsigned char *deltaPtr, *deltaPtrStart = pc+5;
	    Tcl_Obj **wordv = tosPtr - (numWords - 1);
	    int objIdx, wordIdx, wordToExpand = -1;

	    /* 
	     * Compute number of objects needed to store the 
	     * command after expansion is complete.
	     */

	    opnd = objc = numWords;
	    for (deltaPtr = deltaPtrStart; *deltaPtr; deltaPtr++) {
		int numElements;
		wordToExpand += TclGetUInt1AtPtr(deltaPtr);
		Tcl_ListObjLength(NULL, wordv[wordToExpand], &numElements);
		objc += numElements - 1;
	    }

	    /*
	     * We'll store the expanded command in the stack expansion
	     * space just above tosPtr, assuming there is room.  Otherwise,
	     * allocate enough heap storage to store the expanded command.
	     */

	    objv = stackObjArray = tosPtr + 1;
	    if (objc > spaceAvailable) {
		objv = (Tcl_Obj **) ckalloc((unsigned)
			(objc * sizeof(Tcl_Obj *)));
	    } else {
		tosPtr += objc;
	    }

	    objIdx = 0;
	    deltaPtr = deltaPtrStart;
	    wordToExpand = TclGetUInt1AtPtr(deltaPtr) - 1;
	    for (wordIdx = 0; wordIdx < numWords; wordIdx++) {

		/* 
		 * Copy words (expanding some) from wordv to objv.
		 * Note that we do not increment refCounts.  We
		 * rely on the references in wordv (on the execution
		 * stack) to be sufficient to keep the values around
		 * as long as we need them.
		 */

		if (wordIdx == wordToExpand) {
		    int i, numElements;
		    Tcl_Obj **elements, *temp = wordv[wordIdx];

		    /*
		     * Make sure the list we expand is unshared.
		     * If it is not shared, then the stack holds the
		     * only reference to it, and there is no danger
		     * the list will shimmer to another type (and
		     * possibly free the elements of the list) before
		     * we are done with the command evaluation.
		     */

		    if (Tcl_IsShared(temp)) {
			Tcl_DecrRefCount(temp);
			temp = Tcl_DuplicateObj(temp);
			Tcl_IncrRefCount(temp);
			wordv[wordIdx] = temp;
		    }
		    Tcl_ListObjGetElements(NULL, temp, &numElements, &elements);
		    for (i=0; i<numElements; i++) {
			objv[objIdx++] = elements[i];
		    }
		    ++deltaPtr;
		    if (*deltaPtr) {
			wordToExpand += TclGetUInt1AtPtr(deltaPtr);
		    } else {
			wordToExpand = -1;
		    }
		} else {
		    objv[objIdx++] = wordv[wordIdx];
		}
	    }
	    pcAdjustment = (deltaPtr - pc) + 1;
	    goto doInvocation;
	}

    case INST_INVOKE_STK4:
	opnd = TclGetUInt4AtPtr(pc+1);
	objc = opnd;
	objv = stackObjArray = (tosPtr - (objc-1));
	pcAdjustment = 5;
	goto doInvocation;

    case INST_INVOKE_STK1:
	opnd = TclGetUInt1AtPtr(pc+1);
	objc = opnd;
	objv = stackObjArray = (tosPtr - (objc-1));
	pcAdjustment = 2;
	    
    doInvocation:
	{



	    /*
	     * We keep the stack reference count as a (char *), as that
	     * works nicely as a portable pointer-sized counter.
	     */

	    char **preservedStackRefCountPtr;
	    








#ifdef TCL_COMPILE_DEBUG
	    if (tclTraceExec >= 2) {
		if (traceInstructions) {
		    strncpy(cmdNameBuf, TclGetString(objv[0]), 20);
		    TRACE(("%u => call ", objc));
		} else {
		    fprintf(stdout, "%d: (%u) invoking ",
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
	     * because all others are liable to change due to the
	     * trace procedures.
	     */

	    preservedStackRefCountPtr = (char **) (eePtr->stackPtr-1);
	    ++*preservedStackRefCountPtr;









	    /*
	     * Finally, let TclEvalObjvInternal handle the command. 
	     */

	    DECACHE_STACK_INFO();
	    Tcl_ResetResult(interp);
	    result = TclEvalObjvInternal(interp, objc, objv, bytes, length, 0);
	    CACHE_STACK_INFO();

	    /*
	     * If the old stack is going to be released, it is
	     * safe to do so now, since no references to objv are
	     * going to be used from now on.
	     */

	    --*preservedStackRefCountPtr;
	    if (*preservedStackRefCountPtr == (char *) 0) {
		ckfree((VOID *) preservedStackRefCountPtr);
	    }	    







	    if (result == TCL_OK) {
		/*
		 * Push the call's object result and continue execution
		 * with the next instruction.
		 */








>
>
>
>
>
>
>
>



















>
>
>
>
>
>







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
	     * because all others are liable to change due to the
	     * trace procedures.
	     */

	    preservedStackRefCountPtr = (char **) (eePtr->stackPtr-1);
	    ++*preservedStackRefCountPtr;

	    /*
	     * Reset the instructionCount variable, since we're about
	     * to check for async stuff anyway while processing
	     * TclEvalObjvInternal.
	     */

	    instructionCount = 1;

	    /*
	     * Finally, let TclEvalObjvInternal handle the command. 
	     */

	    DECACHE_STACK_INFO();
	    Tcl_ResetResult(interp);
	    result = TclEvalObjvInternal(interp, objc, objv, bytes, length, 0);
	    CACHE_STACK_INFO();

	    /*
	     * If the old stack is going to be released, it is
	     * safe to do so now, since no references to objv are
	     * going to be used from now on.
	     */

	    --*preservedStackRefCountPtr;
	    if (*preservedStackRefCountPtr == (char *) 0) {
		ckfree((VOID *) preservedStackRefCountPtr);
	    }	    

	    if (objv != stackObjArray) {
		ckfree((char *) objv);
	    } else if (*pc == INST_INVOKE_EXP) {
		tosPtr -= objc;
	    }

	    if (result == TCL_OK) {
		/*
		 * Push the call's object result and continue execution
		 * with the next instruction.
		 */

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
	pcAdjustment = 2;                      /* FALSE */
	    
    doJumpTrue:
	{
	    int b;
		
	    valuePtr = *tosPtr;





	    if (valuePtr->typePtr == &tclIntType) {




		b = (valuePtr->internalRep.longValue != 0);
	    } else if (valuePtr->typePtr == &tclDoubleType) {
		b = (valuePtr->internalRep.doubleValue != 0.0);
	    } else if (valuePtr->typePtr == &tclWideIntType) {
		TclGetWide(w,valuePtr);
		b = (w != W0);
	    } else {
		result = Tcl_GetBooleanFromObj(interp, valuePtr, &b);
		if (result != TCL_OK) {
		    TRACE_WITH_OBJ(("%d => ERROR: ", opnd), Tcl_GetObjResult(interp));
		    goto checkForCatch;
		}
	    }
#ifndef TCL_COMPILE_DEBUG
	    NEXT_INST_F((b? opnd : pcAdjustment), 1, 0);
#else
	    if (b) {
		if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE1)) {
		    TRACE(("%d => %.20s true, new pc %u\n", opnd, O2S(valuePtr),
		            (unsigned int)(pc+opnd - codePtr->codeStart)));
		} else {
		    TRACE(("%d => %.20s true\n", pcAdjustment, O2S(valuePtr)));
		}
		NEXT_INST_F(opnd, 1, 0);
	    } else {
		if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE1)) {
		    TRACE(("%d => %.20s false\n", opnd, O2S(valuePtr)));
		} else {
		    opnd = pcAdjustment;
		    TRACE(("%d => %.20s false, new pc %u\n", opnd, O2S(valuePtr),
		            (unsigned int)(pc + opnd - codePtr->codeStart)));
		}
		NEXT_INST_F(pcAdjustment, 1, 0);
	    }
#endif
	}
	    	    





    case INST_LOR:
    case INST_LAND:
    {
	/*
	 * Operands must be boolean or numeric. No int->double
	 * conversions are performed.
	 */







>
>
>
>
>
|
>
>
>
>

















|







|











>
>
>
>
>







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
	pcAdjustment = 2;                      /* FALSE */
	    
    doJumpTrue:
	{
	    int b;
		
	    valuePtr = *tosPtr;
	    /*
	     * The following will be partially resolved at compile 
	     * time and optimised away.
	     */
	    if (((sizeof(long) == sizeof(int)) &&
		         (valuePtr->typePtr == &tclIntType))
		    || (valuePtr->typePtr == &tclBooleanType)) {
		b = (int) valuePtr->internalRep.longValue;
	    } else if ((sizeof(long) != sizeof(int)) &&
		        (valuePtr->typePtr == &tclIntType)) {
		b = (valuePtr->internalRep.longValue != 0);
	    } else if (valuePtr->typePtr == &tclDoubleType) {
		b = (valuePtr->internalRep.doubleValue != 0.0);
	    } else if (valuePtr->typePtr == &tclWideIntType) {
		TclGetWide(w,valuePtr);
		b = (w != W0);
	    } else {
		result = Tcl_GetBooleanFromObj(interp, valuePtr, &b);
		if (result != TCL_OK) {
		    TRACE_WITH_OBJ(("%d => ERROR: ", opnd), Tcl_GetObjResult(interp));
		    goto checkForCatch;
		}
	    }
#ifndef TCL_COMPILE_DEBUG
	    NEXT_INST_F((b? opnd : pcAdjustment), 1, 0);
#else
	    if (b) {
		if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE4)) {
		    TRACE(("%d => %.20s true, new pc %u\n", opnd, O2S(valuePtr),
		            (unsigned int)(pc+opnd - codePtr->codeStart)));
		} else {
		    TRACE(("%d => %.20s true\n", pcAdjustment, O2S(valuePtr)));
		}
		NEXT_INST_F(opnd, 1, 0);
	    } else {
		if ((*pc == INST_JUMP_TRUE1) || (*pc == INST_JUMP_TRUE4)) {
		    TRACE(("%d => %.20s false\n", opnd, O2S(valuePtr)));
		} else {
		    opnd = pcAdjustment;
		    TRACE(("%d => %.20s false, new pc %u\n", opnd, O2S(valuePtr),
		            (unsigned int)(pc + opnd - codePtr->codeStart)));
		}
		NEXT_INST_F(pcAdjustment, 1, 0);
	    }
#endif
	}
	    	    
    /*
     * These two instructions are now redundant: the complete logic of the
     * LOR and LAND is now handled by the expression compiler.
     */

    case INST_LOR:
    case INST_LAND:
    {
	/*
	 * Operands must be boolean or numeric. No int->double
	 * conversions are performed.
	 */
2331
2332
2333
2334
2335
2336
2337











































2338
2339
2340
2341
2342
2343
2344

	/*
	 * Stash the list element on the stack
	 */
	TRACE(("%.20s %.20s => %s\n",
	        O2S(valuePtr), O2S(value2Ptr), O2S(objResultPtr)));
	NEXT_INST_F(1, 2, -1); /* already has the correct refCount */












































    case INST_LIST_INDEX_MULTI:
    {
	/*
	 * 'lindex' with multiple index args:
	 *
	 * Determine the count of index args.







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







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

	/*
	 * Stash the list element on the stack
	 */
	TRACE(("%.20s %.20s => %s\n",
	        O2S(valuePtr), O2S(value2Ptr), O2S(objResultPtr)));
	NEXT_INST_F(1, 2, -1); /* already has the correct refCount */

    case INST_LIST_INDEX_IMM:
    {
	/*** lindex with objc==3 and index in bytecode stream ***/

	int listc, idx;
	Tcl_Obj **listv;

	/*
	 * Pop the list and get the index
	 */
	valuePtr = *tosPtr;
	opnd = TclGetInt4AtPtr(pc+1);

	/*
	 * Get the contents of the list, making sure that it
	 * really is a list in the process.
	 */
	result = Tcl_ListObjGetElements(interp, valuePtr, &listc, &listv);
	if (result != TCL_OK) {
	    TRACE_WITH_OBJ(("\"%.30s\" %d => ERROR: ", O2S(valuePtr), opnd),
		    Tcl_GetObjResult(interp));
	    goto checkForCatch;
	}

	/*
	 * Select the list item based on the index.  Negative
	 * operand == end-based indexing.
	 */
	if (opnd < -1) {
	    idx = opnd+1 + listc;
	} else {
	    idx = opnd;
	}
	if (idx >= 0 && idx < listc) {
	    objResultPtr = listv[idx];
	} else {
	    TclNewObj(objResultPtr);
	}

	TRACE_WITH_OBJ(("\"%.30s\" %d => ", O2S(valuePtr), opnd), objResultPtr);
	NEXT_INST_F(5, 1, 1);
    }

    case INST_LIST_INDEX_MULTI:
    {
	/*
	 * 'lindex' with multiple index args:
	 *
	 * Determine the count of index args.
2451
2452
2453
2454
2455
2456
2457












































































2458
2459
2460
2461
2462
2463
2464
	}

	/*
	 * Set result
	 */
	TRACE(("=> %s\n", O2S(objResultPtr)));
	NEXT_INST_F(1, 2, -1);













































































    /*
     *     End of INST_LIST and related instructions.
     * ---------------------------------------------------------
     */

    case INST_STR_EQ:







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







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
	}

	/*
	 * Set result
	 */
	TRACE(("=> %s\n", O2S(objResultPtr)));
	NEXT_INST_F(1, 2, -1);

    case INST_LIST_RANGE_IMM:
    {
	/*** lrange with objc==4 and both indices in bytecode stream ***/

	int listc, fromIdx, toIdx;
	Tcl_Obj **listv;

	/*
	 * Pop the list and get the indices
	 */
	valuePtr = *tosPtr;
	fromIdx = TclGetInt4AtPtr(pc+1);
	toIdx = TclGetInt4AtPtr(pc+5);

	/*
	 * Get the contents of the list, making sure that it
	 * really is a list in the process.
	 */
	result = Tcl_ListObjGetElements(interp, valuePtr, &listc, &listv);
	if (result != TCL_OK) {
	    TRACE_WITH_OBJ(("\"%.30s\" %d %d => ERROR: ", O2S(valuePtr),
		    fromIdx, toIdx), Tcl_GetObjResult(interp));
	    goto checkForCatch;
	}

	/*
	 * Skip a lot of work if we're about to throw the result away
	 * (common with uses of [lassign].)
	 */
#ifndef TCL_COMPILE_DEBUG
	if (*(pc+9) == INST_POP) {
	    NEXT_INST_F(10, 1, 0);
	}
#endif

	/*
	 * Adjust the indices for end-based handling.
	 */
	if (fromIdx < -1) {
	    fromIdx += 1+listc;
	    if (fromIdx < -1) {
		fromIdx = -1;
	    }
	} else if (fromIdx > listc) {
	    fromIdx = listc;
	}
	if (toIdx < -1) {
	    toIdx += 1+listc;
	    if (toIdx < -1) {
		toIdx = -1;
	    }
	} else if (toIdx > listc) {
	    toIdx = listc;
	}

	/*
	 * Check if we are referring to a valid, non-empty list range,
	 * and if so, build the list of elements in that range.
	 */
	if (fromIdx<=toIdx && fromIdx<listc && toIdx>=0) {
	    if (fromIdx<0) {
		fromIdx = 0;
	    }
	    if (toIdx >= listc) {
		toIdx = listc-1;
	    }
	    objResultPtr = Tcl_NewListObj(toIdx-fromIdx+1, listv+fromIdx);
	} else {
	    TclNewObj(objResultPtr);
	}

	TRACE_WITH_OBJ(("\"%.30s\" %d %d => ", O2S(valuePtr),
		TclGetInt4AtPtr(pc+1), TclGetInt4AtPtr(pc+5)), objResultPtr);
	NEXT_INST_F(9, 1, 1);
    }

    /*
     *     End of INST_LIST and related instructions.
     * ---------------------------------------------------------
     */

    case INST_STR_EQ:
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
	     * Call one of the built-in Tcl math functions.
	     */

	    BuiltinFunc *mathFuncPtr;

	    if ((opnd < 0) || (opnd > LAST_BUILTIN_FUNC)) {
		TRACE(("UNRECOGNIZED BUILTIN FUNC CODE %d\n", opnd));
		panic("TclExecuteByteCode: unrecognized builtin function code %d", opnd);
	    }
	    mathFuncPtr = &(tclBuiltinFuncTable[opnd]);
	    DECACHE_STACK_INFO();
	    result = (*mathFuncPtr->proc)(interp, eePtr,
	            mathFuncPtr->clientData);
	    CACHE_STACK_INFO();
	    if (result != TCL_OK) {







|







4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
	     * Call one of the built-in Tcl math functions.
	     */

	    BuiltinFunc *mathFuncPtr;

	    if ((opnd < 0) || (opnd > LAST_BUILTIN_FUNC)) {
		TRACE(("UNRECOGNIZED BUILTIN FUNC CODE %d\n", opnd));
		Tcl_Panic("TclExecuteByteCode: unrecognized builtin function code %d", opnd);
	    }
	    mathFuncPtr = &(tclBuiltinFuncTable[opnd]);
	    DECACHE_STACK_INFO();
	    result = (*mathFuncPtr->proc)(interp, eePtr,
	            mathFuncPtr->clientData);
	    CACHE_STACK_INFO();
	    if (result != TCL_OK) {
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125

    case INST_PUSH_RETURN_CODE:
	objResultPtr = Tcl_NewLongObj(result);
	TRACE(("=> %u\n", result));
	NEXT_INST_F(1, 0, 1);

    default:
	panic("TclExecuteByteCode: unrecognized opCode %u", *pc);
    } /* end of switch on opCode */

    /*
     * Division by zero in an expression. Control only reaches this
     * point by "goto divideByZero".
     */
	







|







4391
4392
4393
4394
4395
4396
4397
4398
4399
4400
4401
4402
4403
4404
4405

    case INST_PUSH_RETURN_CODE:
	objResultPtr = Tcl_NewLongObj(result);
	TRACE(("=> %u\n", result));
	NEXT_INST_F(1, 0, 1);

    default:
	Tcl_Panic("TclExecuteByteCode: unrecognized opCode %u", *pc);
    } /* end of switch on opCode */

    /*
     * Division by zero in an expression. Control only reaches this
     * point by "goto divideByZero".
     */
	
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
4322
4323
	    TclDecrRefCount(valuePtr);
	}
	if (tosPtr < initTosPtr) {
	    fprintf(stderr, "\nTclExecuteByteCode: abnormal return at pc %u: stack top %d < entry stack top %d\n",
		    (unsigned int)(pc - codePtr->codeStart),
		    (unsigned int) (tosPtr - eePtr->stackPtr),
		    (unsigned int) initStackTop);
	    panic("TclExecuteByteCode execution failure: end stack top < start stack top");
	}
	eePtr->tosPtr = initTosPtr - codePtr->maxExceptDepth;
    }
    return result;
}

#ifdef TCL_COMPILE_DEBUG







|







4589
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
4600
4601
4602
4603
	    TclDecrRefCount(valuePtr);
	}
	if (tosPtr < initTosPtr) {
	    fprintf(stderr, "\nTclExecuteByteCode: abnormal return at pc %u: stack top %d < entry stack top %d\n",
		    (unsigned int)(pc - codePtr->codeStart),
		    (unsigned int) (tosPtr - eePtr->stackPtr),
		    (unsigned int) initStackTop);
	    Tcl_Panic("TclExecuteByteCode execution failure: end stack top < start stack top");
	}
	eePtr->tosPtr = initTosPtr - codePtr->maxExceptDepth;
    }
    return result;
}

#ifdef TCL_COMPILE_DEBUG
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
    unsigned int codeEnd = (unsigned int)
	    (codePtr->codeStart + codePtr->numCodeBytes);
    unsigned char opCode = *pc;

    if (((unsigned int) pc < codeStart) || ((unsigned int) pc > codeEnd)) {
	fprintf(stderr, "\nBad instruction pc 0x%x in TclExecuteByteCode\n",
		(unsigned int) pc);
	panic("TclExecuteByteCode execution failure: bad pc");
    }
    if ((unsigned int) opCode > LAST_INST_OPCODE) {
	fprintf(stderr, "\nBad opcode %d at pc %u in TclExecuteByteCode\n",
		(unsigned int) opCode, relativePc);
        panic("TclExecuteByteCode execution failure: bad opcode");
    }
    if ((stackTop < stackLowerBound) || (stackTop > stackUpperBound)) {
	int numChars;
	char *cmd = GetSrcInfoForPc(pc, codePtr, &numChars);
	char *ellipsis = "";
	
	fprintf(stderr, "\nBad stack top %d at pc %u in TclExecuteByteCode (min %i, max %i)",
		stackTop, relativePc, stackLowerBound, stackUpperBound);
	if (cmd != NULL) {
	    Tcl_Obj *message = Tcl_NewStringObj("\n executing ", -1);
	    Tcl_IncrRefCount(message);
	    TclAppendLimitedToObj(message, cmd, numChars, 100, NULL);
	    fprintf(stderr,"%s\n", Tcl_GetString(message));
	    Tcl_DecrRefCount(message);
	} else {
	    fprintf(stderr, "\n");
	}
	panic("TclExecuteByteCode execution failure: bad stack top");
    }
}
#endif /* TCL_COMPILE_DEBUG */

/*
 *----------------------------------------------------------------------
 *







|




|




<












|







4702
4703
4704
4705
4706
4707
4708
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718

4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
    unsigned int codeEnd = (unsigned int)
	    (codePtr->codeStart + codePtr->numCodeBytes);
    unsigned char opCode = *pc;

    if (((unsigned int) pc < codeStart) || ((unsigned int) pc > codeEnd)) {
	fprintf(stderr, "\nBad instruction pc 0x%x in TclExecuteByteCode\n",
		(unsigned int) pc);
	Tcl_Panic("TclExecuteByteCode execution failure: bad pc");
    }
    if ((unsigned int) opCode > LAST_INST_OPCODE) {
	fprintf(stderr, "\nBad opcode %d at pc %u in TclExecuteByteCode\n",
		(unsigned int) opCode, relativePc);
        Tcl_Panic("TclExecuteByteCode execution failure: bad opcode");
    }
    if ((stackTop < stackLowerBound) || (stackTop > stackUpperBound)) {
	int numChars;
	char *cmd = GetSrcInfoForPc(pc, codePtr, &numChars);

	
	fprintf(stderr, "\nBad stack top %d at pc %u in TclExecuteByteCode (min %i, max %i)",
		stackTop, relativePc, stackLowerBound, stackUpperBound);
	if (cmd != NULL) {
	    Tcl_Obj *message = Tcl_NewStringObj("\n executing ", -1);
	    Tcl_IncrRefCount(message);
	    TclAppendLimitedToObj(message, cmd, numChars, 100, NULL);
	    fprintf(stderr,"%s\n", Tcl_GetString(message));
	    Tcl_DecrRefCount(message);
	} else {
	    fprintf(stderr, "\n");
	}
	Tcl_Panic("TclExecuteByteCode execution failure: bad stack top");
    }
}
#endif /* TCL_COMPILE_DEBUG */

/*
 *----------------------------------------------------------------------
 *
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		"unknown math function \"", funcName, "\"", (char *) NULL);
	result = TCL_ERROR;
	goto done;
    }
    mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
    if (mathFuncPtr->numArgs != (objc-1)) {
	panic("ExprCallMathFunc: expected number of args %d != actual number %d",
	        mathFuncPtr->numArgs, objc);
	result = TCL_ERROR;
	goto done;
    }

    /*
     * Collect the arguments for the function, if there are any, into the







|







5918
5919
5920
5921
5922
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
	Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
		"unknown math function \"", funcName, "\"", (char *) NULL);
	result = TCL_ERROR;
	goto done;
    }
    mathFuncPtr = (MathFunc *) Tcl_GetHashValue(hPtr);
    if (mathFuncPtr->numArgs != (objc-1)) {
	Tcl_Panic("ExprCallMathFunc: expected number of args %d != actual number %d",
	        mathFuncPtr->numArgs, objc);
	result = TCL_ERROR;
	goto done;
    }

    /*
     * Collect the arguments for the function, if there are any, into the
Changes to generic/tclFCmd.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 * tclFCmd.c
 *
 *      This file implements the generic portion of file manipulation 
 *      subcommands of the "file" command. 
 *
 * Copyright (c) 1996-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.
 *
 * RCS: @(#) $Id: tclFCmd.c,v 1.21.2.1 2003/06/24 17:27:41 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * Declarations for local procedures defined in this file:











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 * tclFCmd.c
 *
 *      This file implements the generic portion of file manipulation 
 *      subcommands of the "file" command. 
 *
 * Copyright (c) 1996-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.
 *
 * RCS: @(#) $Id: tclFCmd.c,v 1.21.2.2 2004/02/07 05:48:00 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * Declarations for local procedures defined in this file:
237
238
239
240
241
242
243

244
245
246
247
248
249
250
    for (i = 2; i < objc; i++) {
	if (Tcl_FSConvertToPathType(interp, objv[i]) != TCL_OK) {
	    result = TCL_ERROR;
	    break;
	}

	split = Tcl_FSSplitPath(objv[i],&pobjc);

	if (pobjc == 0) {
	    errno = ENOENT;
	    errfile = objv[i];
	    break;
	}
	for (j = 0; j < pobjc; j++) {
	    target = Tcl_FSJoinPath(split, j + 1);







>







237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
    for (i = 2; i < objc; i++) {
	if (Tcl_FSConvertToPathType(interp, objv[i]) != TCL_OK) {
	    result = TCL_ERROR;
	    break;
	}

	split = Tcl_FSSplitPath(objv[i],&pobjc);
	Tcl_IncrRefCount(split);
	if (pobjc == 0) {
	    errno = ENOENT;
	    errfile = objv[i];
	    break;
	}
	for (j = 0; j < pobjc; j++) {
	    target = Tcl_FSJoinPath(split, j + 1);
520
521
522
523
524
525
526
















527
528
529
530
531
532
533
	        && S_ISDIR(targetStatBuf.st_mode)) {
	    errno = EISDIR;
	    Tcl_AppendResult(interp, "can't overwrite directory \"", 
		    Tcl_GetString(target), "\" with file \"", 
		    Tcl_GetString(source), "\"", (char *) NULL);
	    goto done;
	}
















    }

    if (copyFlag == 0) {
	result = Tcl_FSRenameFile(source, target);
	if (result == TCL_OK) {
	    goto done;
	}







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







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
	        && S_ISDIR(targetStatBuf.st_mode)) {
	    errno = EISDIR;
	    Tcl_AppendResult(interp, "can't overwrite directory \"", 
		    Tcl_GetString(target), "\" with file \"", 
		    Tcl_GetString(source), "\"", (char *) NULL);
	    goto done;
	}
	
	/* 
	 * The destination exists, but appears to be ok to over-write,
	 * and -force is given.  We now try to adjust permissions to
	 * ensure the operation succeeds.  If we can't adjust
	 * permissions, we'll let the actual copy/rename return
	 * an error later.
	 */
#if !defined(__WIN32__) && !defined(MAC_TCL)
	{
	Tcl_Obj* perm = Tcl_NewStringObj("u+w",-1);
	Tcl_IncrRefCount(perm);
	Tcl_FSFileAttrsSet(NULL, 2, target, perm);
	Tcl_DecrRefCount(perm);
	}
#endif
    }

    if (copyFlag == 0) {
	result = Tcl_FSRenameFile(source, target);
	if (result == TCL_OK) {
	    goto done;
	}
549
550
551
552
553
554
555
556
557
558
559






560
561


562
563
564
565
566
567
568
	 * the low-level Tcl_FSRenameFileProc in the filesystem is allowed 
	 * to implement cross-filesystem moves itself, if it desires.
	 */
    }

    actualSource = source;
    Tcl_IncrRefCount(actualSource);
#if 0
#ifdef S_ISLNK
    /* 
     * To add a flag to make 'copy' copy links instead of files, we could






     * add a condition to ignore this 'if' here.
     */


    if (copyFlag && S_ISLNK(sourceStatBuf.st_mode)) {
	/* 
	 * We want to copy files not links.  Therefore we must follow the
	 * link.  There are two purposes to this 'stat' call here.  First
	 * we want to know if the linked-file/dir actually exists, and
	 * second, in the block of code which follows, some 20 lines
	 * down, we want to check if the thing is a file or directory.







<
<

|
>
>
>
>
>
>
|

>
>







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
	 * the low-level Tcl_FSRenameFileProc in the filesystem is allowed 
	 * to implement cross-filesystem moves itself, if it desires.
	 */
    }

    actualSource = source;
    Tcl_IncrRefCount(actualSource);


    /* 
     * Activate the following block to copy files instead of links.
     * However Tcl's semantics currently say we should copy links, so
     * any such change should be the subject of careful study on 
     * the consequences.
     * 
     * Perhaps there could be an optional flag to 'file copy' to
     * dictate which approach to use, with the default being _not_
     * to have this block active.
     */
#if 0
#ifdef S_ISLNK
    if (copyFlag && S_ISLNK(sourceStatBuf.st_mode)) {
	/* 
	 * We want to copy files not links.  Therefore we must follow the
	 * link.  There are two purposes to this 'stat' call here.  First
	 * we want to know if the linked-file/dir actually exists, and
	 * second, in the block of code which follows, some 20 lines
	 * down, we want to check if the thing is a file or directory.
577
578
579
580
581
582
583











584
585
586
587
588
589
590
	} else {
	    int counter = 0;
	    while (1) {
		Tcl_Obj *path = Tcl_FSLink(actualSource, NULL, 0);
		if (path == NULL) {
		    break;
		}











		Tcl_DecrRefCount(actualSource);
		actualSource = path;
		counter++;
		/* Arbitrary limit of 20 links to follow */
		if (counter > 20) {
		    /* Too many links */
		    Tcl_SetErrno(EMLINK);







>
>
>
>
>
>
>
>
>
>
>







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
	} else {
	    int counter = 0;
	    while (1) {
		Tcl_Obj *path = Tcl_FSLink(actualSource, NULL, 0);
		if (path == NULL) {
		    break;
		}
		/* 
		 * Now we want to check if this is a relative path,
		 * and if so, to make it absolute
		 */
		if (Tcl_FSGetPathType(path) == TCL_PATH_RELATIVE) {
		    Tcl_Obj *abs = Tcl_FSJoinToPath(actualSource, 1, &path);
		    if (abs == NULL) break;
		    Tcl_IncrRefCount(abs);
		    Tcl_DecrRefCount(path);
		    path = abs;
		}
		Tcl_DecrRefCount(actualSource);
		actualSource = path;
		counter++;
		/* Arbitrary limit of 20 links to follow */
		if (counter > 20) {
		    /* Too many links */
		    Tcl_SetErrno(EMLINK);
792
793
794
795
796
797
798

799
800
801
802
803
804
805
806

807
808
809
810
811
812
813
    Tcl_Obj *pathPtr;		/* Path whose basename to extract. */
{
    int objc;
    Tcl_Obj *splitPtr;
    Tcl_Obj *resultPtr = NULL;
    
    splitPtr = Tcl_FSSplitPath(pathPtr, &objc);


    if (objc != 0) {
	if ((objc == 1) && (*Tcl_GetString(pathPtr) == '~')) {
	    Tcl_DecrRefCount(splitPtr);
	    if (Tcl_FSConvertToPathType(interp, pathPtr) != TCL_OK) {
		return NULL;
	    }
	    splitPtr = Tcl_FSSplitPath(pathPtr, &objc);

	}

	/*
	 * Return the last component, unless it is the only component, and it
	 * is the root of an absolute path.
	 */








>
|







>







826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
    Tcl_Obj *pathPtr;		/* Path whose basename to extract. */
{
    int objc;
    Tcl_Obj *splitPtr;
    Tcl_Obj *resultPtr = NULL;
    
    splitPtr = Tcl_FSSplitPath(pathPtr, &objc);
    Tcl_IncrRefCount(splitPtr);
    
    if (objc != 0) {
	if ((objc == 1) && (*Tcl_GetString(pathPtr) == '~')) {
	    Tcl_DecrRefCount(splitPtr);
	    if (Tcl_FSConvertToPathType(interp, pathPtr) != TCL_OK) {
		return NULL;
	    }
	    splitPtr = Tcl_FSSplitPath(pathPtr, &objc);
	    Tcl_IncrRefCount(splitPtr);
	}

	/*
	 * Return the last component, unless it is the only component, and it
	 * is the root of an absolute path.
	 */

Changes to generic/tclFileName.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclFileName.c --
 *
 *	This file contains routines for converting file names betwen
 *	native and network form.
 *
 * Copyright (c) 1995-1998 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.
 *
 * RCS: @(#) $Id: tclFileName.c,v 1.41.2.2 2003/10/16 02:28:02 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include "tclRegexp.h"

/* 












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclFileName.c --
 *
 *	This file contains routines for converting file names betwen
 *	native and network form.
 *
 * Copyright (c) 1995-1998 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.
 *
 * RCS: @(#) $Id: tclFileName.c,v 1.41.2.3 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include "tclRegexp.h"

/* 
71
72
73
74
75
76
77
78
79
80
81
82




83
84
85
86
87
88
89
 */

static CONST char *	DoTildeSubst _ANSI_ARGS_((Tcl_Interp *interp,
			    CONST char *user, Tcl_DString *resultPtr));
static CONST char *	ExtractWinRoot _ANSI_ARGS_((CONST char *path,
			    Tcl_DString *resultPtr, int offset, 
			    Tcl_PathType *typePtr));
static int		SkipToChar _ANSI_ARGS_((char **stringPtr,
			    char *match));
static Tcl_Obj*		SplitMacPath _ANSI_ARGS_((CONST char *path));
static Tcl_Obj*		SplitWinPath _ANSI_ARGS_((CONST char *path));
static Tcl_Obj*		SplitUnixPath _ANSI_ARGS_((CONST char *path));




#ifdef MAC_UNDERSTANDS_UNIX_PATHS

/*
 *----------------------------------------------------------------------
 *
 * FileNameInit --
 *







|
<



>
>
>
>







71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
86
87
88
89
90
91
92
 */

static CONST char *	DoTildeSubst _ANSI_ARGS_((Tcl_Interp *interp,
			    CONST char *user, Tcl_DString *resultPtr));
static CONST char *	ExtractWinRoot _ANSI_ARGS_((CONST char *path,
			    Tcl_DString *resultPtr, int offset, 
			    Tcl_PathType *typePtr));
static int		SkipToChar _ANSI_ARGS_((char **stringPtr, int match));

static Tcl_Obj*		SplitMacPath _ANSI_ARGS_((CONST char *path));
static Tcl_Obj*		SplitWinPath _ANSI_ARGS_((CONST char *path));
static Tcl_Obj*		SplitUnixPath _ANSI_ARGS_((CONST char *path));
static int              DoGlob _ANSI_ARGS_((Tcl_Interp *interp, 
			    char *separators, Tcl_Obj *pathPtr, 
			    int flags, char *pattern, Tcl_GlobTypeData *types));

#ifdef MAC_UNDERSTANDS_UNIX_PATHS

/*
 *----------------------------------------------------------------------
 *
 * FileNameInit --
 *
343
344
345
346
347
348
349
350
351
352

353
354
355
356
357
358
359
360
361
362
363
364
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

Tcl_PathType
TclpGetNativePathType(pathObjPtr, driveNameLengthPtr, driveNameRef)
    Tcl_Obj *pathObjPtr;
    int *driveNameLengthPtr;

    Tcl_Obj **driveNameRef;
{
    Tcl_PathType type = TCL_PATH_ABSOLUTE;
    int pathLen;
    char *path = Tcl_GetStringFromObj(pathObjPtr, &pathLen);
    
    if (path[0] == '~') {
	/* 
	 * This case is common to all platforms.
	 * Paths that begin with ~ are absolute.
	 */
	if (driveNameLengthPtr != NULL) {







|
|
|
>
|



|







346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

Tcl_PathType
TclpGetNativePathType(pathPtr, driveNameLengthPtr, driveNameRef)
    Tcl_Obj *pathPtr;      /* Native path of interest */
    int *driveNameLengthPtr;  /* Returns length of drive, if non-NULL
                               * and path was absolute */
    Tcl_Obj **driveNameRef;   
{
    Tcl_PathType type = TCL_PATH_ABSOLUTE;
    int pathLen;
    char *path = Tcl_GetStringFromObj(pathPtr, &pathLen);
    
    if (path[0] == '~') {
	/* 
	 * This case is common to all platforms.
	 * Paths that begin with ~ are absolute.
	 */
	if (driveNameLengthPtr != NULL) {
607
608
609
610
611
612
613

614
615
616
617
618
619
620
    /*
     * Perform the splitting, using objectified, vfs-aware code.
     */

    tmpPtr = Tcl_NewStringObj(path, -1);
    Tcl_IncrRefCount(tmpPtr);
    resultPtr = Tcl_FSSplitPath(tmpPtr, argcPtr);

    Tcl_DecrRefCount(tmpPtr);

    /* Calculate space required for the result */
    
    size = 1;
    for (i = 0; i < *argcPtr; i++) {
	Tcl_ListObjIndex(NULL, resultPtr, i, &eltPtr);







>







611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
    /*
     * Perform the splitting, using objectified, vfs-aware code.
     */

    tmpPtr = Tcl_NewStringObj(path, -1);
    Tcl_IncrRefCount(tmpPtr);
    resultPtr = Tcl_FSSplitPath(tmpPtr, argcPtr);
    Tcl_IncrRefCount(resultPtr);
    Tcl_DecrRefCount(tmpPtr);

    /* Calculate space required for the result */
    
    size = 1;
    for (i = 0; i < *argcPtr; i++) {
	Tcl_ListObjIndex(NULL, resultPtr, i, &eltPtr);
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
 *---------------------------------------------------------------------------
 *
 * Tcl_FSJoinToPath --
 *
 *      This function takes the given object, which should usually be a
 *      valid path or NULL, and joins onto it the array of paths
 *      segments given.
 *





 * Results:
 *      Returns object with refCount of zero

 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */

Tcl_Obj* 
Tcl_FSJoinToPath(basePtr, objc, objv)
    Tcl_Obj *basePtr;
    int objc;
    Tcl_Obj *CONST objv[];
{
    int i;
    Tcl_Obj *lobj, *ret;

    if (basePtr == NULL) {
	lobj = Tcl_NewListObj(0, NULL);
    } else {
	lobj = Tcl_NewListObj(1, &basePtr);
    }
    
    for (i = 0; i<objc;i++) {
	Tcl_ListObjAppendElement(NULL, lobj, objv[i]);
    }
    ret = Tcl_FSJoinPath(lobj, -1);









    Tcl_DecrRefCount(lobj);

    return ret;
}

/*
 *---------------------------------------------------------------------------
 *
 * TclpNativeJoinPath --







|
>
>
>
>
>

|
>








|
|
|
|




|


|






>
>
>
>
>
>
>
>
>

>







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
 *---------------------------------------------------------------------------
 *
 * Tcl_FSJoinToPath --
 *
 *      This function takes the given object, which should usually be a
 *      valid path or NULL, and joins onto it the array of paths
 *      segments given.
 *      
 *      The objects in the array given will temporarily have their
 *      refCount increased by one, and then decreased by one when this
 *      function exits (which means if they had zero refCount when we
 *      were called, they will be freed).
 *      
 * Results:
 *      Returns object owned by the caller (which should increment its
 *      refCount) - typically an object with refCount of zero.
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */

Tcl_Obj* 
Tcl_FSJoinToPath(pathPtr, objc, objv)
    Tcl_Obj *pathPtr;      /* Valid path or NULL. */
    int objc;              /* Number of array elements to join */
    Tcl_Obj *CONST objv[]; /* Path elements to join. */
{
    int i;
    Tcl_Obj *lobj, *ret;

    if (pathPtr == NULL) {
	lobj = Tcl_NewListObj(0, NULL);
    } else {
	lobj = Tcl_NewListObj(1, &pathPtr);
    }
    
    for (i = 0; i<objc;i++) {
	Tcl_ListObjAppendElement(NULL, lobj, objv[i]);
    }
    ret = Tcl_FSJoinPath(lobj, -1);
    /*
     * It is possible that 'ret' is just a member of the list and is
     * therefore going to be freed here.  Therefore we must adjust the
     * refCount manually.  (It would be better if we changed the
     * documentation of this function and Tcl_FSJoinPath so that
     * the returned object already has a refCount for the caller,
     * hence avoiding these subtleties (and code ugliness)). 
     */
    Tcl_IncrRefCount(ret);
    Tcl_DecrRefCount(lobj);
    ret->refCount--;
    return ret;
}

/*
 *---------------------------------------------------------------------------
 *
 * TclpNativeJoinPath --
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

char *
TclGetExtension(name)
    char *name;			/* File name to parse. */
{
    char *p, *lastSep;

    /*
     * First find the last directory separator.
     */

    lastSep = NULL;		/* Needed only to prevent gcc warnings. */
    switch (tclPlatform) {







|

|

|







1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

CONST char *
TclGetExtension(name)
    CONST char *name;			/* File name to parse. */
{
    CONST char *p, *lastSep;

    /*
     * First find the last directory separator.
     */

    lastSep = NULL;		/* Needed only to prevent gcc warnings. */
    switch (tclPlatform) {
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
    enum pathDirOptions {PATH_NONE = -1 , PATH_GENERAL = 0, PATH_DIR = 1};
    Tcl_GlobTypeData *globTypes = NULL;

    globFlags = 0;
    join = 0;
    dir = PATH_NONE;
    typePtr = NULL;
    resultPtr = Tcl_GetObjResult(interp);
    for (i = 1; i < objc; i++) {
	if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0, &index)
		!= TCL_OK) {
	    string = Tcl_GetStringFromObj(objv[i], &length);
	    if (string[0] == '-') {
		/*
		 * It looks like the command contains an option so signal







<







1602
1603
1604
1605
1606
1607
1608

1609
1610
1611
1612
1613
1614
1615
    enum pathDirOptions {PATH_NONE = -1 , PATH_GENERAL = 0, PATH_DIR = 1};
    Tcl_GlobTypeData *globTypes = NULL;

    globFlags = 0;
    join = 0;
    dir = PATH_NONE;
    typePtr = NULL;

    for (i = 1; i < objc; i++) {
	if (Tcl_GetIndexFromObj(interp, objv[i], options, "option", 0, &index)
		!= TCL_OK) {
	    string = Tcl_GetStringFromObj(objv[i], &length);
	    if (string[0] == '-') {
		/*
		 * It looks like the command contains an option so signal
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
	}
	switch (index) {
	    case GLOB_NOCOMPLAIN:			/* -nocomplain */
	        globFlags |= TCL_GLOBMODE_NO_COMPLAIN;
		break;
	    case GLOB_DIR:				/* -dir */
		if (i == (objc-1)) {
		    Tcl_AppendToObj(resultPtr,
			    "missing argument to \"-directory\"", -1);
		    return TCL_ERROR;
		}
		if (dir != PATH_NONE) {
		    Tcl_AppendToObj(resultPtr,
			    "\"-directory\" cannot be used with \"-path\"",
			    -1);
		    return TCL_ERROR;
		}
		dir = PATH_DIR;
		globFlags |= TCL_GLOBMODE_DIR;
		pathOrDir = objv[i+1];
		i++;
		break;
	    case GLOB_JOIN:				/* -join */
		join = 1;
		break;
	    case GLOB_TAILS:				/* -tails */
	        globFlags |= TCL_GLOBMODE_TAILS;
		break;
	    case GLOB_PATH:				/* -path */
	        if (i == (objc-1)) {
		    Tcl_AppendToObj(resultPtr,
			    "missing argument to \"-path\"", -1);
		    return TCL_ERROR;
		}
		if (dir != PATH_NONE) {
		    Tcl_AppendToObj(resultPtr,
			    "\"-path\" cannot be used with \"-directory\"",
			    -1);
		    return TCL_ERROR;
		}
		dir = PATH_GENERAL;
		pathOrDir = objv[i+1];
		i++;
		break;
	    case GLOB_TYPE:				/* -types */
	        if (i == (objc-1)) {
		    Tcl_AppendToObj(resultPtr,
			    "missing argument to \"-types\"", -1);
		    return TCL_ERROR;
		}
		typePtr = objv[i+1];
		if (Tcl_ListObjLength(interp, typePtr, &length) != TCL_OK) {
		    return TCL_ERROR;
		}
		i++;
		break;
	    case GLOB_LAST:				/* -- */
	        i++;
		goto endOfForLoop;
	}
    }
    endOfForLoop:
    if (objc - i < 1) {
        Tcl_WrongNumArgs(interp, 1, objv, "?switches? name ?name ...?");
	return TCL_ERROR;
    }
    if ((globFlags & TCL_GLOBMODE_TAILS) && (pathOrDir == NULL)) {
	Tcl_AppendToObj(resultPtr,
	  "\"-tails\" must be used with either \"-directory\" or \"-path\"",
	  -1);
	return TCL_ERROR;
    }
    
    separators = NULL;		/* lint. */
    switch (tclPlatform) {
	case TCL_PLATFORM_UNIX:
	    separators = "/";







|
|



|

|















|
|



|

|








|
|



















|

|







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
	}
	switch (index) {
	    case GLOB_NOCOMPLAIN:			/* -nocomplain */
	        globFlags |= TCL_GLOBMODE_NO_COMPLAIN;
		break;
	    case GLOB_DIR:				/* -dir */
		if (i == (objc-1)) {
		    Tcl_SetObjResult(interp, Tcl_NewStringObj(
			    "missing argument to \"-directory\"", -1));
		    return TCL_ERROR;
		}
		if (dir != PATH_NONE) {
		    Tcl_SetObjResult(interp, Tcl_NewStringObj(
			    "\"-directory\" cannot be used with \"-path\"",
			    -1));
		    return TCL_ERROR;
		}
		dir = PATH_DIR;
		globFlags |= TCL_GLOBMODE_DIR;
		pathOrDir = objv[i+1];
		i++;
		break;
	    case GLOB_JOIN:				/* -join */
		join = 1;
		break;
	    case GLOB_TAILS:				/* -tails */
	        globFlags |= TCL_GLOBMODE_TAILS;
		break;
	    case GLOB_PATH:				/* -path */
	        if (i == (objc-1)) {
		    Tcl_SetObjResult(interp, Tcl_NewStringObj(
			    "missing argument to \"-path\"", -1));
		    return TCL_ERROR;
		}
		if (dir != PATH_NONE) {
		    Tcl_SetObjResult(interp, Tcl_NewStringObj(
			    "\"-path\" cannot be used with \"-directory\"",
			    -1));
		    return TCL_ERROR;
		}
		dir = PATH_GENERAL;
		pathOrDir = objv[i+1];
		i++;
		break;
	    case GLOB_TYPE:				/* -types */
	        if (i == (objc-1)) {
		    Tcl_SetObjResult(interp, Tcl_NewStringObj(
			    "missing argument to \"-types\"", -1));
		    return TCL_ERROR;
		}
		typePtr = objv[i+1];
		if (Tcl_ListObjLength(interp, typePtr, &length) != TCL_OK) {
		    return TCL_ERROR;
		}
		i++;
		break;
	    case GLOB_LAST:				/* -- */
	        i++;
		goto endOfForLoop;
	}
    }
    endOfForLoop:
    if (objc - i < 1) {
        Tcl_WrongNumArgs(interp, 1, objv, "?switches? name ?name ...?");
	return TCL_ERROR;
    }
    if ((globFlags & TCL_GLOBMODE_TAILS) && (pathOrDir == NULL)) {
	Tcl_SetObjResult(interp, Tcl_NewStringObj(
	  "\"-tails\" must be used with either \"-directory\" or \"-path\"",
	  -1));
	return TCL_ERROR;
    }
    
    separators = NULL;		/* lint. */
    switch (tclPlatform) {
	case TCL_PLATFORM_UNIX:
	    separators = "/";
1707
1708
1709
1710
1711
1712
1713

1714





1715

1716
1717
1718
1719
1720
1721
1722
	    /* It's really a directory */
	    dir = PATH_DIR;
	} else {
	    Tcl_DString pref;
	    char *search, *find;
	    Tcl_DStringInit(&pref);
	    if (last == first) {

		/* The whole thing is a prefix */





		Tcl_DStringAppend(&pref, first, -1);

		pathOrDir = NULL;
	    } else {
		/* Have to split off the end */
		Tcl_DStringAppend(&pref, last, first+pathlength-last);
		pathOrDir = Tcl_NewStringObj(first, last-first-1);
	    }
	    /* Need to quote 'prefix' */







>
|
>
>
>
>
>

>







1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
	    /* It's really a directory */
	    dir = PATH_DIR;
	} else {
	    Tcl_DString pref;
	    char *search, *find;
	    Tcl_DStringInit(&pref);
	    if (last == first) {
		/* 
		 * The whole thing is a prefix.  This means we must
		 * remove any 'tails' flag too, since it is irrelevant
		 * now (the same effect will happen without it), but in
		 * particular its use in TclGlob requires a non-NULL
		 * pathOrDir.
		 */
		Tcl_DStringAppend(&pref, first, -1);
		globFlags &= ~TCL_GLOBMODE_TAILS;
		pathOrDir = NULL;
	    } else {
		/* Have to split off the end */
		Tcl_DStringAppend(&pref, last, first+pathlength-last);
		pathOrDir = Tcl_NewStringObj(first, last-first-1);
	    }
	    /* Need to quote 'prefix' */
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
			    globTypes->macCreator = item;
			    Tcl_IncrRefCount(item);
			    continue;
			}
		    }
		}
		/*
		 * Error cases.  We re-get the interpreter's result,
		 * just to be sure it hasn't changed, and we reset
		 * the 'join' flag to zero, since we haven't yet
		 * made use of it.
		 */
		badTypesArg:
		resultPtr = Tcl_GetObjResult(interp);
		Tcl_AppendToObj(resultPtr, "bad argument to \"-types\": ", -1);
		Tcl_AppendObjToObj(resultPtr, look);
		result = TCL_ERROR;
		join = 0;
		goto endOfGlob;
		badMacTypesArg:
		resultPtr = Tcl_GetObjResult(interp);
		Tcl_AppendToObj(resultPtr,
		   "only one MacOS type or creator argument"
		   " to \"-types\" allowed", -1);
		result = TCL_ERROR;
		join = 0;
		goto endOfGlob;
	    }
	}
    }

    /* 
     * Now we perform the actual glob below.  This may involve joining
     * together the pattern arguments, dealing with particular file types
     * etc.  We use a 'goto' to ensure we free any memory allocated along
     * the way.
     */
    objc -= i;
    objv += i;
    /* 
     * We re-retrieve this, in case it was changed in 
     * the Tcl_ResetResult above 
     */
    resultPtr = Tcl_GetObjResult(interp);
    result = TCL_OK;
    if (join) {
	if (dir != PATH_GENERAL) {
	    Tcl_DStringInit(&prefix);
	}
	for (i = 0; i < objc; i++) {
	    string = Tcl_GetStringFromObj(objv[i], &length);







|
<











|
<

|















<
<
<
<
<







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
			    globTypes->macCreator = item;
			    Tcl_IncrRefCount(item);
			    continue;
			}
		    }
		}
		/*
		 * Error cases.  We reset

		 * the 'join' flag to zero, since we haven't yet
		 * made use of it.
		 */
		badTypesArg:
		resultPtr = Tcl_GetObjResult(interp);
		Tcl_AppendToObj(resultPtr, "bad argument to \"-types\": ", -1);
		Tcl_AppendObjToObj(resultPtr, look);
		result = TCL_ERROR;
		join = 0;
		goto endOfGlob;
		badMacTypesArg:
		Tcl_SetObjResult(interp, Tcl_NewStringObj(

		   "only one MacOS type or creator argument"
		   " to \"-types\" allowed", -1));
		result = TCL_ERROR;
		join = 0;
		goto endOfGlob;
	    }
	}
    }

    /* 
     * Now we perform the actual glob below.  This may involve joining
     * together the pattern arguments, dealing with particular file types
     * etc.  We use a 'goto' to ensure we free any memory allocated along
     * the way.
     */
    objc -= i;
    objv += i;





    result = TCL_OK;
    if (join) {
	if (dir != PATH_GENERAL) {
	    Tcl_DStringInit(&prefix);
	}
	for (i = 0; i < objc; i++) {
	    string = Tcl_GetStringFromObj(objv[i], &length);
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975




1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034



2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088



2089
2090

2091
2092
2093
2094
2095



2096
2097
2098



2099
2100
2101
2102



2103



2104









2105
2106
2107
2108









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
}

/*
 *----------------------------------------------------------------------
 *
 * TclGlob --
 *
 *	This procedure prepares arguments for the TclDoGlob call.
 *	It sets the separator string based on the platform, performs
 *      tilde substitution, and calls TclDoGlob.
 *      
 *      The interpreter's result, on entry to this function, must
 *      be a valid Tcl list (e.g. it could be empty), since we will
 *      lappend any new results to that list.  If it is not a valid
 *      list, this function will fail to do anything very meaningful.




 *
 * Results:
 *	The return value is a standard Tcl result indicating whether
 *	an error occurred in globbing.  After a normal return the
 *	result in interp (set by TclDoGlob) holds all of the file names
 *	given by the pattern and unquotedPrefix arguments.  After an 
 *	error the result in interp will hold an error message, unless
 *	the 'TCL_GLOBMODE_NO_COMPLAIN' flag was given, in which case
 *	an error results in a TCL_OK return leaving the interpreter's
 *	result unmodified.
 *
 * Side effects:
 *	The 'pattern' is written to.
 *
 *----------------------------------------------------------------------
 */

	/* ARGSUSED */
int
TclGlob(interp, pattern, unquotedPrefix, globFlags, types)
    Tcl_Interp *interp;		/* Interpreter for returning error message
				 * or appending list of matching file names. */
    char *pattern;		/* Glob pattern to match. Must not refer
				 * to a static string. */
    Tcl_Obj *unquotedPrefix;	/* Prefix to glob pattern, if non-null, which
                             	 * is considered literally. */
    int globFlags;		/* Stores or'ed combination of flags */
    Tcl_GlobTypeData *types;	/* Struct containing acceptable types.
				 * May be NULL. */
{
    char *separators;
    CONST char *head;
    char *tail, *start;
    char c;
    int result, prefixLen;
    Tcl_DString buffer;
    Tcl_Obj *oldResult;

    separators = NULL;		/* lint. */
    switch (tclPlatform) {
	case TCL_PLATFORM_UNIX:
	    separators = "/";
	    break;
	case TCL_PLATFORM_WINDOWS:
	    separators = "/\\:";
	    break;
	case TCL_PLATFORM_MAC:
#ifdef MAC_UNDERSTANDS_UNIX_PATHS
	    if (unquotedPrefix == NULL) {
		separators = (strchr(pattern, ':') == NULL) ? "/" : ":";
	    } else {
		separators = ":";
	    }
#else
	    separators = ":";
#endif
	    break;
    }




    Tcl_DStringInit(&buffer);
    if (unquotedPrefix != NULL) {
	start = Tcl_GetString(unquotedPrefix);
    } else {
	start = pattern;
    }

    /*
     * Perform tilde substitution, if needed.
     */

    if (start[0] == '~') {
	
	/*
	 * Find the first path separator after the tilde.
	 */
	for (tail = start; *tail != '\0'; tail++) {
	    if (*tail == '\\') {
		if (strchr(separators, tail[1]) != NULL) {
		    break;
		}
	    } else if (strchr(separators, *tail) != NULL) {
		break;
	    }
	}

	/*
	 * Determine the home directory for the specified user.  
	 */
	
	c = *tail;
	*tail = '\0';
	if (globFlags & TCL_GLOBMODE_NO_COMPLAIN) {
	    /* 
	     * We will ignore any error message here, and we
	     * don't want to mess up the interpreter's result.
	     */
	    head = DoTildeSubst(NULL, start+1, &buffer);
	} else {
	    head = DoTildeSubst(interp, start+1, &buffer);
	}
	*tail = c;
	if (head == NULL) {
	    if (globFlags & TCL_GLOBMODE_NO_COMPLAIN) {
		return TCL_OK;
	    } else {
		return TCL_ERROR;
	    }
	}
	if (head != Tcl_DStringValue(&buffer)) {
	    Tcl_DStringAppend(&buffer, head, -1);
	}
	if (unquotedPrefix != NULL) {
	    Tcl_DStringAppend(&buffer, tail, -1);



	    tail = pattern;
	}

    } else {
	tail = pattern;
	if (unquotedPrefix != NULL) {
	    Tcl_DStringAppend(&buffer,Tcl_GetString(unquotedPrefix),-1);
	}



    }
    
    /* 



     * We want to remember the length of the current prefix,
     * in case we are using TCL_GLOBMODE_TAILS.  Also if we
     * are using TCL_GLOBMODE_DIR, we must make sure the
     * prefix ends in a directory separator.



     */



    prefixLen = Tcl_DStringLength(&buffer);










    if (prefixLen > 0) {
	c = Tcl_DStringValue(&buffer)[prefixLen-1];
	if (strchr(separators, c) == NULL) {









	    /* 
	     * If the prefix is a directory, make sure it ends in a
	     * directory separator.

	     */
	    if (globFlags & TCL_GLOBMODE_DIR) {
		Tcl_DStringAppend(&buffer,separators,1);
	    }



	    prefixLen++;

	}
    }

    /* 
     * We need to get the old result, in case it is over-written
     * below when we still need it.
     */
    oldResult = Tcl_GetObjResult(interp);
    Tcl_IncrRefCount(oldResult);
    Tcl_ResetResult(interp);
    








    result = TclDoGlob(interp, separators, &buffer, tail, types);


    
    if (result != TCL_OK) {
	if (globFlags & TCL_GLOBMODE_NO_COMPLAIN) {
	    /* Put back the old result and reset the return code */
	    Tcl_SetObjResult(interp, oldResult);
	    result = TCL_OK;
	}
    } else {
	/* 
	 * Now we must concatenate the 'oldResult' and the current
	 * result, and then place that into the interpreter.
	 * 
	 * If we only want the tails, we must strip off the prefix now.
	 * It may seem more efficient to pass the tails flag down into
	 * TclDoGlob, Tcl_FSMatchInDirectory, but those functions are
	 * continually adjusting the prefix as the various pieces of
	 * the pattern are assimilated, so that would add a lot of
	 * complexity to the code.  This way is a little slower (when
	 * the -tails flag is given), but much simpler to code.
	 */
	int objc, i;
	Tcl_Obj **objv;


	/* Ensure sole ownership */


	if (Tcl_IsShared(oldResult)) {
	    Tcl_DecrRefCount(oldResult);
	    oldResult = Tcl_DuplicateObj(oldResult);
	    Tcl_IncrRefCount(oldResult);
	}














	Tcl_ListObjGetElements(NULL, Tcl_GetObjResult(interp), 
			       &objc, &objv);
#ifdef MAC_TCL
	/* adjust prefixLen if TclDoGlob prepended a ':' */
	if ((prefixLen > 0) && (objc > 0)
	&& (Tcl_DStringValue(&buffer)[0] != ':')) {
	    char *str = Tcl_GetStringFromObj(objv[0],NULL);
	    if (str[0] == ':') {
		    prefixLen++;
	    }
	}
#endif
	for (i = 0; i< objc; i++) {
	    Tcl_Obj* elt;
	    if (globFlags & TCL_GLOBMODE_TAILS) {
		int len;
		char *oldStr = Tcl_GetStringFromObj(objv[i],&len);
		if (len == prefixLen) {
		    if ((pattern[0] == '\0')
			|| (strchr(separators, pattern[0]) == NULL)) {
			elt = Tcl_NewStringObj(".",1);
		    } else {
			elt = Tcl_NewStringObj("/",1);
		    }
		} else {
		    elt = Tcl_NewStringObj(oldStr + prefixLen, 
						len - prefixLen);
		}
	    } else {
		elt = objv[i];
	    }
	    /* Assumption that 'oldResult' is a valid list */

	    Tcl_ListObjAppendElement(interp, oldResult, elt);
	}
	Tcl_SetObjResult(interp, oldResult);
    }
    /* 
     * Release our temporary copy.  All code paths above must
     * end here so we free our reference.
     */
    Tcl_DecrRefCount(oldResult);
    Tcl_DStringFree(&buffer);
    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * SkipToChar --







|

|





>
>
>
>




|
|













|




|
|







<
|
<

|










|










>
>
>
|
|
<
<

<
<
|
|
|

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

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

>
>
>



>
>
>
|
<
<
|
>
>
>

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


|







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














|





<
<

>
|
>
>






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

|
|
|
|
|
<













|
<

<
>
|








<







1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032

2033

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


2062


2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
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
}

/*
 *----------------------------------------------------------------------
 *
 * TclGlob --
 *
 *	This procedure prepares arguments for the DoGlob call.
 *	It sets the separator string based on the platform, performs
 *      tilde substitution, and calls DoGlob.
 *      
 *      The interpreter's result, on entry to this function, must
 *      be a valid Tcl list (e.g. it could be empty), since we will
 *      lappend any new results to that list.  If it is not a valid
 *      list, this function will fail to do anything very meaningful.
 *      
 *      Note that if globFlags contains 'TCL_GLOBMODE_TAILS' then
 *      pathPrefix cannot be NULL (it is only allowed with -dir or
 *      -path).
 *
 * Results:
 *	The return value is a standard Tcl result indicating whether
 *	an error occurred in globbing.  After a normal return the
 *	result in interp (set by DoGlob) holds all of the file names
 *	given by the pattern and pathPrefix arguments.  After an 
 *	error the result in interp will hold an error message, unless
 *	the 'TCL_GLOBMODE_NO_COMPLAIN' flag was given, in which case
 *	an error results in a TCL_OK return leaving the interpreter's
 *	result unmodified.
 *
 * Side effects:
 *	The 'pattern' is written to.
 *
 *----------------------------------------------------------------------
 */

	/* ARGSUSED */
int
TclGlob(interp, pattern, pathPrefix, globFlags, types)
    Tcl_Interp *interp;		/* Interpreter for returning error message
				 * or appending list of matching file names. */
    char *pattern;		/* Glob pattern to match. Must not refer
				 * to a static string. */
    Tcl_Obj *pathPrefix;	/* Path prefix to glob pattern, if non-null, 
                        	 * which is considered literally. */
    int globFlags;		/* Stores or'ed combination of flags */
    Tcl_GlobTypeData *types;	/* Struct containing acceptable types.
				 * May be NULL. */
{
    char *separators;
    CONST char *head;
    char *tail, *start;

    int result;

    Tcl_Obj *oldResult;
    
    separators = NULL;		/* lint. */
    switch (tclPlatform) {
	case TCL_PLATFORM_UNIX:
	    separators = "/";
	    break;
	case TCL_PLATFORM_WINDOWS:
	    separators = "/\\:";
	    break;
	case TCL_PLATFORM_MAC:
#ifdef MAC_UNDERSTANDS_UNIX_PATHS
	    if (pathPrefix == NULL) {
		separators = (strchr(pattern, ':') == NULL) ? "/" : ":";
	    } else {
		separators = ":";
	    }
#else
	    separators = ":";
#endif
	    break;
    }

    if (pathPrefix == NULL) {
	char c;
	Tcl_DString buffer;
	Tcl_DStringInit(&buffer);



	start = pattern;


	/*
	 * Perform tilde substitution, if needed.
	 */

	if (start[0] == '~') {
	    
	    /*
	     * Find the first path separator after the tilde.
	     */
	    for (tail = start; *tail != '\0'; tail++) {
		if (*tail == '\\') {
		    if (strchr(separators, tail[1]) != NULL) {
			break;
		    }
		} else if (strchr(separators, *tail) != NULL) {
		    break;
		}
	    }

	    /*
	     * Determine the home directory for the specified user.  
	     */
	    
	    c = *tail;
	    *tail = '\0';
	    if (globFlags & TCL_GLOBMODE_NO_COMPLAIN) {
		/* 
		 * We will ignore any error message here, and we
		 * don't want to mess up the interpreter's result.
		 */
		head = DoTildeSubst(NULL, start+1, &buffer);
	    } else {
		head = DoTildeSubst(interp, start+1, &buffer);
	    }
	    *tail = c;
	    if (head == NULL) {
		if (globFlags & TCL_GLOBMODE_NO_COMPLAIN) {
		    return TCL_OK;
		} else {
		    return TCL_ERROR;
		}
	    }
	    if (head != Tcl_DStringValue(&buffer)) {
		Tcl_DStringAppend(&buffer, head, -1);
	    }
	    pathPrefix = Tcl_NewStringObj(Tcl_DStringValue(&buffer),
					  Tcl_DStringLength(&buffer));
	    Tcl_IncrRefCount(pathPrefix);
	    globFlags |= TCL_GLOBMODE_DIR;
	    if (c != '\0') {
	        tail++;
	    }
	    Tcl_DStringFree(&buffer);
	} else {
	    tail = pattern;


	}
    } else {
	Tcl_IncrRefCount(pathPrefix);
	tail = pattern;
    }
    
    /* 
     * Handling empty path prefixes with glob patterns like 'C:' or
     * 'c:////////' is a pain on Windows if we leave it too late, since
     * these aren't really patterns at all!  We therefore check the head
     * of the pattern now for such cases, if we don't have an unquoted


     * prefix yet.
     * 
     * Similarly on Unix with '/' at the head of the pattern -- it
     * just indicates the root volume, so we treat it as such.
     */
    if (tclPlatform == TCL_PLATFORM_WINDOWS) {
	if (pathPrefix == NULL && tail[0] != '\0' && tail[1] == ':') {
	    char *p = tail + 1;
	    pathPrefix = Tcl_NewStringObj(tail, 1);
	    while (*p != '\0') {
		char c = p[1];
	        if (*p == '\\') {
	            if (strchr(separators, c) != NULL) {
			if (c == '\\') c = '/';
			Tcl_AppendToObj(pathPrefix, &c, 1);
			p++;
	            } else {
			break;
		    }


		} else if (strchr(separators, *p) != NULL) {
		    Tcl_AppendToObj(pathPrefix, p, 1);
	        } else {
		    break;
		}
		p++;
	    }
	    tail = p;
	    Tcl_IncrRefCount(pathPrefix);
	}
	/* 

	 * ':' no longer needed as a separator. It is only relevant
	 * to the beginning of the path.
	 */

	separators = "/\\";

    } else if (tclPlatform == TCL_PLATFORM_UNIX) {
	if (pathPrefix == NULL && tail[0] == '/') {
	    pathPrefix = Tcl_NewStringObj(tail, 1);
	    tail++;
	    Tcl_IncrRefCount(pathPrefix);
	}
    }
    
    /* 
     * We need to get the old result, in case it is over-written
     * below when we still need it.
     */
    oldResult = Tcl_GetObjResult(interp);
    Tcl_IncrRefCount(oldResult);
    Tcl_ResetResult(interp);

    if (*tail == '\0' && pathPrefix != NULL) {
	/* 
	 * An empty pattern 
	 */
	result = Tcl_FSMatchInDirectory(interp, Tcl_GetObjResult(interp), 
					pathPrefix, NULL, types);
	
    } else {
	result = DoGlob(interp, separators, pathPrefix, 
			globFlags & TCL_GLOBMODE_DIR, tail, types);
    }
    
    if (result != TCL_OK) {
	if (globFlags & TCL_GLOBMODE_NO_COMPLAIN) {
	    /* Put back the old result and reset the return code */
	    Tcl_SetObjResult(interp, oldResult);
	    result = TCL_OK;
	}
    } else {
	/* 
	 * Now we must concatenate the 'oldResult' and the current
	 * result, and then place that into the interpreter.
	 * 
	 * If we only want the tails, we must strip off the prefix now.
	 * It may seem more efficient to pass the tails flag down into
	 * DoGlob, Tcl_FSMatchInDirectory, but those functions are
	 * continually adjusting the prefix as the various pieces of
	 * the pattern are assimilated, so that would add a lot of
	 * complexity to the code.  This way is a little slower (when
	 * the -tails flag is given), but much simpler to code.
	 */



	/* 
	 * Ensure sole ownership.  We also assume that oldResult
	 * is a valid list in the code below.
	 */
	if (Tcl_IsShared(oldResult)) {
	    Tcl_DecrRefCount(oldResult);
	    oldResult = Tcl_DuplicateObj(oldResult);
	    Tcl_IncrRefCount(oldResult);
	}

	if (globFlags & TCL_GLOBMODE_TAILS) {
	    int objc, i;
	    Tcl_Obj **objv;
	    int prefixLen;
	    
	    /* If this length has never been set, set it here */
	    CONST char *pre = Tcl_GetStringFromObj(pathPrefix, &prefixLen);
	    if (prefixLen > 0) {
		if (strchr(separators, pre[prefixLen-1]) == NULL) {
		    prefixLen++;
		}
	    }

	    Tcl_ListObjGetElements(NULL, Tcl_GetObjResult(interp), 
				   &objc, &objv);
    #ifdef MAC_TCL
	    /* adjust prefixLen if DoGlob prepended a ':' */
	    if ((prefixLen > 0) && (objc > 0) && (pre[0] != ':')) {

		CONST char *str = Tcl_GetStringFromObj(objv[0],NULL);
		if (str[0] == ':') {
		    prefixLen++;
		}
	    }
    #endif
	    for (i = 0; i< objc; i++) {
		Tcl_Obj* elt;

		int len;
		char *oldStr = Tcl_GetStringFromObj(objv[i],&len);
		if (len == prefixLen) {
		    if ((pattern[0] == '\0')
			|| (strchr(separators, pattern[0]) == NULL)) {
			elt = Tcl_NewStringObj(".",1);
		    } else {
			elt = Tcl_NewStringObj("/",1);
		    }
		} else {
		    elt = Tcl_NewStringObj(oldStr + prefixLen, 
						len - prefixLen);
		}
		Tcl_ListObjAppendElement(interp, oldResult, elt);

	    }

	} else {
	    Tcl_ListObjAppendList(interp, oldResult, Tcl_GetObjResult(interp));
	}
	Tcl_SetObjResult(interp, oldResult);
    }
    /* 
     * Release our temporary copy.  All code paths above must
     * end here so we free our reference.
     */
    Tcl_DecrRefCount(oldResult);

    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * SkipToChar --
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
 *	None.
 *
 *----------------------------------------------------------------------
 */

static int
SkipToChar(stringPtr, match)
    char **stringPtr;			/* Pointer string to check. */
    char *match;			/* Pointer to character to find. */
{
    int quoted, level;
    register char *p;

    quoted = 0;
    level = 0;

    for (p = *stringPtr; *p != '\0'; p++) {
	if (quoted) {
	    quoted = 0;
	    continue;
	}
	if ((level == 0) && (*p == *match)) {
	    *stringPtr = p;
	    return 1;
	}
	if (*p == '{') {
	    level++;
	} else if (*p == '}') {
	    level--;
	} else if (*p == '\\') {
	    quoted = 1;
	}
    }
    *stringPtr = p;
    return 0;
}

/*
 *----------------------------------------------------------------------
 *
 * TclDoGlob --
 *
 *	This recursive procedure forms the heart of the globbing
 *	code.  It performs a depth-first traversal of the tree
 *	given by the path name to be globbed.  The directory and
 *	remainder are assumed to be native format paths.  The prefix 
 *	contained in 'headPtr' is not used as a glob pattern, simply
 *	as a path specifier, so it can contain unquoted glob-sensitive
 *	characters (if the directories to which it points contain
 *	such strange characters).
 *
 * Results:
 *	The return value is a standard Tcl result indicating whether
 *	an error occurred in globbing.  After a normal return the
 *	result in interp will be set to hold all of the file names
 *	given by the dir and rem arguments.  After an error the
 *	result in interp will hold an error message.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

int
TclDoGlob(interp, separators, headPtr, tail, types)
    Tcl_Interp *interp;		/* Interpreter to use for error reporting
				 * (e.g. unmatched brace). */
    char *separators;		/* String containing separator characters
				 * that should be used to identify globbing
				 * boundaries. */
    Tcl_DString *headPtr;	/* Completely expanded prefix. */


    char *tail;			/* The unexpanded remainder of the path.
				 * Must not be a pointer to a static string. */
    Tcl_GlobTypeData *types;	/* List object containing list of acceptable 
                            	 * types. May be NULL. */
{
    int baseLength, quoted, count;
    int result = TCL_OK;
    char *name, *p, *openBrace, *closeBrace, *firstSpecialChar, savedChar;
    char lastChar = 0;
    
    int length = Tcl_DStringLength(headPtr);

    if (length > 0) {
	lastChar = Tcl_DStringValue(headPtr)[length-1];
    }

    /*
     * Consume any leading directory separators, leaving tail pointing
     * just past the last initial separator.
     */

    count = 0;
    name = tail;
    for (; *tail != '\0'; tail++) {
	if (*tail == '\\') {
	    /* 
	     * If the first character is escaped, either we have a directory
	     * separator, or we have any other character.  In the latter case
	     * the rest of tail is a pattern, and we must break from the loop.
	     * This is particularly important on Windows where '\' is both
	     * the escaping character and a directory separator.
	     */
	    if (strchr(separators, tail[1]) != NULL) {
		tail++;
	    } else {
		break;
	    }
	} else if (strchr(separators, *tail) == NULL) {
	    break;
	}
	count++;
    }










    /*
     * Deal with path separators.  On the Mac, we have to watch out
     * for multiple separators, since they are special in Mac-style
     * paths.
     */









    switch (tclPlatform) {
	case TCL_PLATFORM_MAC:
#ifdef MAC_UNDERSTANDS_UNIX_PATHS
	    if (*separators == '/') {
		if (((length == 0) && (count == 0))
			|| ((length > 0) && (lastChar != ':'))) {
		    Tcl_DStringAppend(headPtr, ":", 1);
		}
	    } else {
#endif
		if (count == 0) {
		    if ((length > 0) && (lastChar != ':')) {
			Tcl_DStringAppend(headPtr, ":", 1);
		    }
		} else {
		    if (lastChar == ':') {
			count--;
		    }
		    while (count-- > 0) {
			Tcl_DStringAppend(headPtr, ":", 1);
		    }
		}
#ifdef MAC_UNDERSTANDS_UNIX_PATHS
	    }
#endif
	    break;
	case TCL_PLATFORM_WINDOWS:
	    /*
	     * If this is a drive relative path, add the colon and the
	     * trailing slash if needed.  Otherwise add the slash if
	     * this is the first absolute element, or a later relative
	     * element.  Add an extra slash if this is a UNC path.
	     */

	    if (*name == ':') {
		Tcl_DStringAppend(headPtr, ":", 1);
		if (count > 1) {
		    Tcl_DStringAppend(headPtr, "/", 1);
		}
	    } else if ((*tail != '\0')
		    && (((length > 0)
			    && (strchr(separators, lastChar) == NULL))
			    || ((length == 0) && (count > 0)))) {
		Tcl_DStringAppend(headPtr, "/", 1);
		if ((length == 0) && (count > 1)) {
		    Tcl_DStringAppend(headPtr, "/", 1);
		}
	    }
	    
	    break;
	case TCL_PLATFORM_UNIX:
	    /*
	     * Add a separator if this is the first absolute element, or
	     * a later relative element.
	     */

	    if ((*tail != '\0')
		    && (((length > 0)
			    && (strchr(separators, lastChar) == NULL))
			    || ((length == 0) && (count > 0)))) {
		Tcl_DStringAppend(headPtr, "/", 1);
	    }
	    break;
    }



    /*
     * Look for the first matching pair of braces or the first
     * directory separator that is not inside a pair of braces.
     */

    openBrace = closeBrace = NULL;
    quoted = 0;
    for (p = tail; *p != '\0'; p++) {
	if (quoted) {
	    quoted = 0;
	} else if (*p == '\\') {
	    quoted = 1;
	    if (strchr(separators, p[1]) != NULL) {
		break;			/* Quoted directory separator. */

	    }
	} else if (strchr(separators, *p) != NULL) {
	    break;			/* Unquoted directory separator. */

	} else if (*p == '{') {
	    openBrace = p;
	    p++;
	    if (SkipToChar(&p, "}")) {

		closeBrace = p;		/* Balanced braces. */
		break;
	    }
	    Tcl_SetResult(interp, "unmatched open-brace in file name",
		    TCL_STATIC);
	    return TCL_ERROR;
	} else if (*p == '}') {
	    Tcl_SetResult(interp, "unmatched close-brace in file name",
		    TCL_STATIC);
	    return TCL_ERROR;
	}
    }

    /*
     * Substitute the alternate patterns from the braces and recurse.
     */

    if (openBrace != NULL) {
	char *element;

	Tcl_DString newName;
	Tcl_DStringInit(&newName);

	/*
	 * For each element within in the outermost pair of braces,
	 * append the element and the remainder to the fixed portion
	 * before the first brace and recursively call TclDoGlob.
	 */

	Tcl_DStringAppend(&newName, tail, openBrace-tail);
	baseLength = Tcl_DStringLength(&newName);
	length = Tcl_DStringLength(headPtr);
	*closeBrace = '\0';
	for (p = openBrace; p != closeBrace; ) {
	    p++;
	    element = p;
	    SkipToChar(&p, ",");
	    Tcl_DStringSetLength(headPtr, length);
	    Tcl_DStringSetLength(&newName, baseLength);
	    Tcl_DStringAppend(&newName, element, p-element);
	    Tcl_DStringAppend(&newName, closeBrace+1, -1);
	    result = TclDoGlob(interp, separators, headPtr, 
			       Tcl_DStringValue(&newName), types);
	    if (result != TCL_OK) {
		break;
	    }
	}
	*closeBrace = '}';
	Tcl_DStringFree(&newName);
	return result;
    }

    /*
     * At this point, there are no more brace substitutions to perform on
     * this path component.  The variable p is pointing at a quoted or
     * unquoted directory separator or the end of the string.  So we need
     * to check for special globbing characters in the current pattern.
     * We avoid modifying tail if p is pointing at the end of the string.










     */

    if (*p != '\0') {

	/*
	 * Note that we are modifying the string in place.  This won't work
	 * if the string is a static.
	 */

	savedChar = *p;
	*p = '\0';
	firstSpecialChar = strpbrk(tail, "*[]?\\");
	*p = savedChar;
    } else {
	firstSpecialChar = strpbrk(tail, "*[]?\\");
    }

    if (firstSpecialChar != NULL) {
	int ret;
	Tcl_Obj *head = Tcl_NewStringObj(Tcl_DStringValue(headPtr),-1);
	Tcl_IncrRefCount(head);
	/*
	 * Look for matching files in the given directory.  The
	 * implementation of this function is platform specific.  For
	 * each file that matches, it will add the match onto the
	 * resultPtr given.
	 */
	if (*p == '\0') {
	    ret = Tcl_FSMatchInDirectory(interp, Tcl_GetObjResult(interp), 
					 head, tail, types);
	} else {
	    Tcl_Obj* resultPtr;

	    /* 
	     * We do the recursion ourselves.  This makes implementing
	     * Tcl_FSMatchInDirectory for each filesystem much easier.
	     */
	    Tcl_GlobTypeData dirOnly = { TCL_GLOB_TYPE_DIR, 0, NULL, NULL };
	    char save = *p;
	    
	    *p = '\0';
	    resultPtr = Tcl_NewListObj(0, NULL);
	    ret = Tcl_FSMatchInDirectory(interp, resultPtr, 
					 head, tail, &dirOnly);
	    *p = save;
	    if (ret == TCL_OK) {
		int resLength;
		ret = Tcl_ListObjLength(interp, resultPtr, &resLength);
		if (ret == TCL_OK) {
		    int i;
		    for (i =0; i< resLength; i++) {
			Tcl_Obj *elt;
			Tcl_DString ds;
			Tcl_ListObjIndex(interp, resultPtr, i, &elt);
			Tcl_DStringInit(&ds);
			Tcl_DStringAppend(&ds, Tcl_GetString(elt), -1);
			if(tclPlatform == TCL_PLATFORM_MAC) {
			    Tcl_DStringAppend(&ds, ":",1);
			} else {			
			    Tcl_DStringAppend(&ds, "/",1);
			}
			ret = TclDoGlob(interp, separators, &ds, p+1, types);
			Tcl_DStringFree(&ds);
			if (ret != TCL_OK) {
			    break;
			}
		    }
		}
	    }
	    Tcl_DecrRefCount(resultPtr);
	}
	Tcl_DecrRefCount(head);
	return ret;




    }
    Tcl_DStringAppend(headPtr, tail, p-tail);
    if (*p != '\0') {

















	return TclDoGlob(interp, separators, headPtr, p, types);


    } else {
	/*
	 * This is the code path reached by a command like 'glob foo'.
	 *
	 * There are no more wildcards in the pattern and no more
	 * unprocessed characters in the tail, so now we can construct
	 * the path, and pass it to Tcl_FSMatchInDirectory with an
	 * empty pattern to verify the existence of the file and check
	 * it is of the correct type (if a 'types' flag it given -- if
	 * no such flag was given, we could just use 'Tcl_FSLStat', but
	 * for simplicity we keep to a common approach).
	 */

	Tcl_Obj *nameObj;












	switch (tclPlatform) {
	    case TCL_PLATFORM_MAC: {
		if (strchr(Tcl_DStringValue(headPtr), ':') == NULL) {
		    Tcl_DStringAppend(headPtr, ":", 1);
		}
		break;
	    }
	    case TCL_PLATFORM_WINDOWS: {
		if (Tcl_DStringLength(headPtr) == 0) {
		    if (((*name == '\\') && (name[1] == '/' || name[1] == '\\'))
			    || (*name == '/')) {
			Tcl_DStringAppend(headPtr, "/", 1);
		    } else {
			Tcl_DStringAppend(headPtr, ".", 1);
		    }
		}
#if defined(__CYGWIN__) && defined(__WIN32__)
		{
		extern int cygwin_conv_to_win32_path 
		    _ANSI_ARGS_((CONST char *, char *));
		char winbuf[MAX_PATH+1];

		cygwin_conv_to_win32_path(Tcl_DStringValue(headPtr), winbuf);
		Tcl_DStringFree(headPtr);
		Tcl_DStringAppend(headPtr, winbuf, -1);
		}
#endif /* __CYGWIN__ && __WIN32__ */
		/* 
		 * Convert to forward slashes.  This is required to pass
		 * some Tcl tests.  We should probably remove the conversions
		 * here and in tclWinFile.c, since they aren't needed since
		 * the dropping of support for Win32s.
		 */
		for (p = Tcl_DStringValue(headPtr); *p != '\0'; p++) {
		    if (*p == '\\') {
			*p = '/';
		    }
		}
		break;
	    }
	    case TCL_PLATFORM_UNIX: {
		if (Tcl_DStringLength(headPtr) == 0) {
		    if ((*name == '\\' && name[1] == '/') || (*name == '/')) {
			Tcl_DStringAppend(headPtr, "/", 1);
		    } else {
			Tcl_DStringAppend(headPtr, ".", 1);
		    }
		}
		break;
	    }
	}
	/* Common for all platforms */


	name = Tcl_DStringValue(headPtr);
	nameObj = Tcl_NewStringObj(name, Tcl_DStringLength(headPtr));

	Tcl_IncrRefCount(nameObj);
	Tcl_FSMatchInDirectory(interp, Tcl_GetObjResult(interp), nameObj, 
			       NULL, types);
	Tcl_DecrRefCount(nameObj);
	return TCL_OK;
    }
}


/*
 *---------------------------------------------------------------------------
 *
 * TclFileDirname
 *
 *	This procedure calculates the directory above a given 
 *	path: basically 'file dirname'.  It is used both by
 *	the 'dirname' subcommand of file and by code in tclIOUtil.c.
 *
 * Results:
 *	NULL if an error occurred, otherwise a Tcl_Obj owned by
 *	the caller (i.e. most likely with refCount 1).
 *
 * Side effects:
 *      None.
 *
 *---------------------------------------------------------------------------
 */

Tcl_Obj*
TclFileDirname(interp, pathPtr)
    Tcl_Interp *interp;		/* Used for error reporting */
    Tcl_Obj *pathPtr;           /* Path to take dirname of */
{
    int splitElements;
    Tcl_Obj *splitPtr;
    Tcl_Obj *splitResultPtr = NULL;

    /* 
     * The behaviour we want here is slightly different to
     * the standard Tcl_FSSplitPath in the handling of home
     * directories; Tcl_FSSplitPath preserves the "~" while 
     * this code computes the actual full path name, if we
     * had just a single component.
     */	    
    splitPtr = Tcl_FSSplitPath(pathPtr, &splitElements);
    if ((splitElements == 1) && (Tcl_GetString(pathPtr)[0] == '~')) {

	Tcl_DecrRefCount(splitPtr);
	splitPtr = Tcl_FSGetNormalizedPath(interp, pathPtr);
	if (splitPtr == NULL) {
	    return NULL;
	}
	splitPtr = Tcl_FSSplitPath(splitPtr, &splitElements);
    }

    /*
     * Return all but the last component.  If there is only one
     * component, return it if the path was non-relative, otherwise
     * return the current directory.
     */

    if (splitElements > 1) {
	splitResultPtr = Tcl_FSJoinPath(splitPtr, splitElements - 1);
    } else if (splitElements == 0 || 
      (Tcl_FSGetPathType(pathPtr) == TCL_PATH_RELATIVE)) {
	splitResultPtr = Tcl_NewStringObj(
		((tclPlatform == TCL_PLATFORM_MAC) ? ":" : "."), 1);
    } else {
	Tcl_ListObjIndex(NULL, splitPtr, 0, &splitResultPtr);
    }
    Tcl_IncrRefCount(splitResultPtr);
    Tcl_DecrRefCount(splitPtr);
    return splitResultPtr;
}

/*
 *---------------------------------------------------------------------------
 *
 * Tcl_AllocStatBuf
 *







|
|












|


















|

|
|
|
|
|
<
<
|
|




|








|
|





|
>
>
|


|



|
<
|
<
<
<
<
<
<

|




|
|
|



|



|
|



|





>
>
>
>
>
>
>
>
>





>
>
>
>
>
>
>
>

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

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

|
|
|
|
|
|
|
|
|
>
>







|





|
>


|
>



|
>
|


















>









|

<




|
<



|
|














|
>
>
>
>
>
>
>
>
>
>









|

|


|




|
<


|





|













|








|

<
<
<
<
<
<
<
|
<








<

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

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

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

<

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







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
 *	None.
 *
 *----------------------------------------------------------------------
 */

static int
SkipToChar(stringPtr, match)
    char **stringPtr;		/* Pointer string to check. */
    int match;			/* Character to find. */
{
    int quoted, level;
    register char *p;

    quoted = 0;
    level = 0;

    for (p = *stringPtr; *p != '\0'; p++) {
	if (quoted) {
	    quoted = 0;
	    continue;
	}
	if ((level == 0) && (*p == match)) {
	    *stringPtr = p;
	    return 1;
	}
	if (*p == '{') {
	    level++;
	} else if (*p == '}') {
	    level--;
	} else if (*p == '\\') {
	    quoted = 1;
	}
    }
    *stringPtr = p;
    return 0;
}

/*
 *----------------------------------------------------------------------
 *
 * DoGlob --
 *
 *	This recursive procedure forms the heart of the globbing code.
 *	It performs a depth-first traversal of the tree given by the
 *	path name to be globbed and the pattern.  The directory and
 *	remainder are assumed to be native format paths.  The prefix
 *	contained in 'pathPtr' is either a directory or path from which


 *	to start the search (or NULL).
 *	
 * Results:
 *	The return value is a standard Tcl result indicating whether
 *	an error occurred in globbing.  After a normal return the
 *	result in interp will be set to hold all of the file names
 *	given by the dir and remaining arguments.  After an error the
 *	result in interp will hold an error message.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

static int
DoGlob(interp, separators, pathPtr, flags, pattern, types)
    Tcl_Interp *interp;		/* Interpreter to use for error reporting
				 * (e.g. unmatched brace). */
    char *separators;		/* String containing separator characters
				 * that should be used to identify globbing
				 * boundaries. */
    Tcl_Obj *pathPtr;	        /* Completely expanded prefix. */
    int flags;                  /* If non-zero then pathPtr is a
                                 * directory */
    char *pattern;		/* The pattern to match against.
				 * Must not be a pointer to a static string. */
    Tcl_GlobTypeData *types;	/* List object containing list of acceptable 
				 * types. May be NULL. */
{
    int baseLength, quoted, count;
    int result = TCL_OK;
    char *name, *p, *openBrace, *closeBrace, *firstSpecialChar;








    /*
     * Consume any leading directory separators, leaving pattern pointing
     * just past the last initial separator.
     */

    count = 0;
    name = pattern;
    for (; *pattern != '\0'; pattern++) {
	if (*pattern == '\\') {
	    /* 
	     * If the first character is escaped, either we have a directory
	     * separator, or we have any other character.  In the latter case
	     * the rest is a pattern, and we must break from the loop.
	     * This is particularly important on Windows where '\' is both
	     * the escaping character and a directory separator.
	     */
	    if (strchr(separators, pattern[1]) != NULL) {
		pattern++;
	    } else {
		break;
	    }
	} else if (strchr(separators, *pattern) == NULL) {
	    break;
	}
	count++;
    }

    /* 
     * This block of code is not exercised by the Tcl test suite as of
     * Tcl 8.5a0.  Simplifications to the calling paths suggest it may
     * not be necessary any more, since path separators are handled
     * elsewhere.  It is left in place in case new bugs are reported
     * (particularly on MacOS)
     */

#if 0
    /*
     * Deal with path separators.  On the Mac, we have to watch out
     * for multiple separators, since they are special in Mac-style
     * paths.
     */
    if (pathPtr == NULL) {
	/* 
	 * Length used to be the length of the prefix, and lastChar
	 * the lastChar of the prefix.  But, none of this is used
	 * any more.
	 */
	int length = 0;
	char lastChar = 0;

	switch (tclPlatform) {
	    case TCL_PLATFORM_MAC:
    #ifdef MAC_UNDERSTANDS_UNIX_PATHS
		if (*separators == '/') {
		    if (((length == 0) && (count == 0))
			    || ((length > 0) && (lastChar != ':'))) {
			Tcl_DStringAppend(&append, ":", 1);
		    }
		} else {
    #endif
		    if (count == 0) {
			if ((length > 0) && (lastChar != ':')) {
			    Tcl_DStringAppend(&append, ":", 1);
			}
		    } else {
			if (lastChar == ':') {
			    count--;
			}
			while (count-- > 0) {
			    Tcl_DStringAppend(&append, ":", 1);
			}
		    }
    #ifdef MAC_UNDERSTANDS_UNIX_PATHS
		}
    #endif
		break;
	    case TCL_PLATFORM_WINDOWS:
		/*
		 * If this is a drive relative path, add the colon and the
		 * trailing slash if needed.  Otherwise add the slash if
		 * this is the first absolute element, or a later relative
		 * element.  Add an extra slash if this is a UNC path.
		 */

		if (*name == ':') {
		    Tcl_DStringAppend(&append, ":", 1);
		    if (count > 1) {
			Tcl_DStringAppend(&append, "/", 1);
		    }
		} else if ((*pattern != '\0')
			&& (((length > 0)
				&& (strchr(separators, lastChar) == NULL))
				|| ((length == 0) && (count > 0)))) {
		    Tcl_DStringAppend(&append, "/", 1);
		    if ((length == 0) && (count > 1)) {
			Tcl_DStringAppend(&append, "/", 1);
		    }
		}
		
		break;
	    case TCL_PLATFORM_UNIX:
		/*
		 * Add a separator if this is the first absolute element, or
		 * a later relative element.
		 */

		if ((*pattern != '\0')
			&& (((length > 0)
				&& (strchr(separators, lastChar) == NULL))
				|| ((length == 0) && (count > 0)))) {
		    Tcl_DStringAppend(&append, "/", 1);
		}
		break;
	}
    }
#endif
    
    /*
     * Look for the first matching pair of braces or the first
     * directory separator that is not inside a pair of braces.
     */

    openBrace = closeBrace = NULL;
    quoted = 0;
    for (p = pattern; *p != '\0'; p++) {
	if (quoted) {
	    quoted = 0;
	} else if (*p == '\\') {
	    quoted = 1;
	    if (strchr(separators, p[1]) != NULL) {
		/* Quoted directory separator. */
		break;			
	    }
	} else if (strchr(separators, *p) != NULL) {
	    /* Unquoted directory separator. */
	    break;
	} else if (*p == '{') {
	    openBrace = p;
	    p++;
	    if (SkipToChar(&p, '}')) {
		/* Balanced braces. */
		closeBrace = p;
		break;
	    }
	    Tcl_SetResult(interp, "unmatched open-brace in file name",
		    TCL_STATIC);
	    return TCL_ERROR;
	} else if (*p == '}') {
	    Tcl_SetResult(interp, "unmatched close-brace in file name",
		    TCL_STATIC);
	    return TCL_ERROR;
	}
    }

    /*
     * Substitute the alternate patterns from the braces and recurse.
     */

    if (openBrace != NULL) {
	char *element;
	
	Tcl_DString newName;
	Tcl_DStringInit(&newName);

	/*
	 * For each element within in the outermost pair of braces,
	 * append the element and the remainder to the fixed portion
	 * before the first brace and recursively call TclDoGlob.
	 */

	Tcl_DStringAppend(&newName, pattern, openBrace-pattern);
	baseLength = Tcl_DStringLength(&newName);

	*closeBrace = '\0';
	for (p = openBrace; p != closeBrace; ) {
	    p++;
	    element = p;
	    SkipToChar(&p, ',');

	    Tcl_DStringSetLength(&newName, baseLength);
	    Tcl_DStringAppend(&newName, element, p-element);
	    Tcl_DStringAppend(&newName, closeBrace+1, -1);
	    result = DoGlob(interp, separators, pathPtr, flags,
			    Tcl_DStringValue(&newName), types);
	    if (result != TCL_OK) {
		break;
	    }
	}
	*closeBrace = '}';
	Tcl_DStringFree(&newName);
	return result;
    }

    /*
     * At this point, there are no more brace substitutions to perform on
     * this path component.  The variable p is pointing at a quoted or
     * unquoted directory separator or the end of the string.  So we need
     * to check for special globbing characters in the current pattern.
     * We avoid modifying pattern if p is pointing at the end of the string.
     * 
     * If we find any globbing characters, then we must call 
     * Tcl_FSMatchInDirectory.  If we're at the end of the string, then
     * that's all we need to do.  If we're not at the end of the
     * string, then we must recurse, so we do that below.
     * 
     * Alternatively, if there are no globbing characters then again
     * there are two cases.  If we're at the end of the string, we just
     * need to check for the given path's existence and type.  If we're
     * not at the end of the string, we recurse.
     */

    if (*p != '\0') {

	/*
	 * Note that we are modifying the string in place.  This won't work
	 * if the string is a static.
	 */

	char savedChar = *p;
	*p = '\0';
	firstSpecialChar = strpbrk(pattern, "*[]?\\");
	*p = savedChar;
    } else {
	firstSpecialChar = strpbrk(pattern, "*[]?\\");
    }

    if (firstSpecialChar != NULL) {
	int ret;


	/*
	 * Look for matching files in the given directory.  The
	 * implementation of this function is filesystem specific.  For
	 * each file that matches, it will add the match onto the
	 * resultPtr given.
	 */
	if (*p == '\0') {
	    ret = Tcl_FSMatchInDirectory(interp, Tcl_GetObjResult(interp), 
					 pathPtr, pattern, types);
	} else {
	    Tcl_Obj* resultPtr;

	    /* 
	     * We do the recursion ourselves.  This makes implementing
	     * Tcl_FSMatchInDirectory for each filesystem much easier.
	     */
	    Tcl_GlobTypeData dirOnly = { TCL_GLOB_TYPE_DIR, 0, NULL, NULL };
	    char save = *p;
	    
	    *p = '\0';
	    resultPtr = Tcl_NewListObj(0, NULL);
	    ret = Tcl_FSMatchInDirectory(interp, resultPtr, 
					 pathPtr, pattern, &dirOnly);
	    *p = save;
	    if (ret == TCL_OK) {
		int resLength;
		ret = Tcl_ListObjLength(interp, resultPtr, &resLength);
		if (ret == TCL_OK) {
		    int i;
		    for (i =0; i< resLength; i++) {
			Tcl_Obj *elt;
			
			Tcl_ListObjIndex(interp, resultPtr, i, &elt);







			ret = DoGlob(interp, separators, elt, 1, p+1, types);

			if (ret != TCL_OK) {
			    break;
			}
		    }
		}
	    }
	    Tcl_DecrRefCount(resultPtr);
	}

	return ret;
    } else {
	/* 
	 * We reach here with no pattern char in current section 
	 */
	

	if (*p != '\0') {
	    Tcl_Obj *joined;
	    int ret;
	    
	    /* 
	     * If it's not the end of the string, we must recurse 
	     */
	    if (pathPtr != NULL) {
		if (flags) {
		    joined = TclNewFSPathObj(pathPtr, pattern, p-pattern);
		} else {
		    joined = Tcl_DuplicateObj(pathPtr);
		    Tcl_AppendToObj(joined, pattern, p-pattern);
		}
	    } else {
		joined = Tcl_NewStringObj(pattern, p-pattern);
	    }
	    Tcl_IncrRefCount(joined);
	    ret = DoGlob(interp, separators, joined, 1, p, types);
	    Tcl_DecrRefCount(joined);
	    return ret;
	} else {
	    /*
	     * This is the code path reached by a command like 'glob foo'.
	     *
	     * There are no more wildcards in the pattern and no more
	     * unprocessed characters in the pattern, so now we can construct
	     * the path, and pass it to Tcl_FSMatchInDirectory with an
	     * empty pattern to verify the existence of the file and check
	     * it is of the correct type (if a 'types' flag it given -- if
	     * no such flag was given, we could just use 'Tcl_FSLStat', but
	     * for simplicity we keep to a common approach).
	     */

	    Tcl_Obj *joined;
	    int length;
	    Tcl_DString append;
	    
	    Tcl_DStringInit(&append);
	    Tcl_DStringAppend(&append, pattern, p-pattern);

	    if (pathPtr != NULL) {
		Tcl_GetStringFromObj(pathPtr, &length);
	    } else {
		length = 0;
	    }

	    switch (tclPlatform) {
		case TCL_PLATFORM_MAC: {
		    if (strchr(Tcl_DStringValue(&append), ':') == NULL) {
			Tcl_DStringAppend(&append, ":", 1);
		    }
		    break;
		}
		case TCL_PLATFORM_WINDOWS: {
		    if (length == 0 && (Tcl_DStringLength(&append) == 0)) {
			if (((*name == '\\') && (name[1] == '/' || name[1] == '\\'))
				|| (*name == '/')) {
			    Tcl_DStringAppend(&append, "/", 1);
			} else {
			    Tcl_DStringAppend(&append, ".", 1);
			}
		    }
    #if defined(__CYGWIN__) && defined(__WIN32__)
		    {
		    extern int cygwin_conv_to_win32_path 
			_ANSI_ARGS_((CONST char *, char *));
		    char winbuf[MAX_PATH+1];

		    cygwin_conv_to_win32_path(Tcl_DStringValue(&append), winbuf);
		    Tcl_DStringFree(&append);
		    Tcl_DStringAppend(&append, winbuf, -1);
		    }
    #endif /* __CYGWIN__ && __WIN32__ */











		    break;
		}
		case TCL_PLATFORM_UNIX: {
		    if (length == 0 && (Tcl_DStringLength(&append) == 0)) {
			if ((*name == '\\' && name[1] == '/') || (*name == '/')) {
			    Tcl_DStringAppend(&append, "/", 1);
			} else {
			    Tcl_DStringAppend(&append, ".", 1);
			}
		    }
		    break;
		}
	    }
	    /* Common for all platforms */
	    if (pathPtr != NULL) {
		if (flags) {
		    joined = TclNewFSPathObj(pathPtr, Tcl_DStringValue(&append), 
					     Tcl_DStringLength(&append));
		} else {
		    joined = Tcl_DuplicateObj(pathPtr);
		    Tcl_AppendToObj(joined, Tcl_DStringValue(&append), 

				    Tcl_DStringLength(&append));

		}

	    } else {
		joined = Tcl_NewStringObj(Tcl_DStringValue(&append), 

























					  Tcl_DStringLength(&append));

	    }


	    Tcl_IncrRefCount(joined);


	    Tcl_DStringFree(&append);


	    Tcl_FSMatchInDirectory(interp, Tcl_GetObjResult(interp), joined, 
				   NULL, types);
	    Tcl_DecrRefCount(joined);


	    return TCL_OK;
	}

    }



















}

/*
 *---------------------------------------------------------------------------
 *
 * Tcl_AllocStatBuf
 *
Changes to generic/tclFileSystem.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclFileSystem.h --
 *
 *	This file contains the common defintions and prototypes for
 *	use by Tcl's filesystem and path handling layers.
 *
 * Copyright (c) 2003 Vince Darley.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclFileSystem.h,v 1.2.2.2 2003/10/16 02:28:02 dgp Exp $
 */

/* 
 * struct FilesystemRecord --
 * 
 * A filesystem record is used to keep track of each
 * filesystem currently registered with the core,











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclFileSystem.h --
 *
 *	This file contains the common defintions and prototypes for
 *	use by Tcl's filesystem and path handling layers.
 *
 * Copyright (c) 2003 Vince Darley.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclFileSystem.h,v 1.2.2.3 2004/02/07 05:48:01 dgp Exp $
 */

/* 
 * struct FilesystemRecord --
 * 
 * A filesystem record is used to keep track of each
 * filesystem currently registered with the core,
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
 * time the corresponding epoch counter changes.
 */
typedef struct ThreadSpecificData {
    int initialized;
    int cwdPathEpoch;
    int filesystemEpoch;
    Tcl_Obj *cwdPathPtr;

    FilesystemRecord *filesystemList;
} ThreadSpecificData;

/* 
 * The internal TclFS API provides routines for handling and
 * manipulating paths efficiently, taking direct advantage of
 * the "path" Tcl_Obj type.
 * 
 * These functions are not exported at all at present.
 */

int      TclFSCwdPointerEquals _ANSI_ARGS_((Tcl_Obj* objPtr));
int	 TclFSMakePathFromNormalized _ANSI_ARGS_((Tcl_Interp *interp, 
		Tcl_Obj *objPtr, ClientData clientData));
int      TclFSNormalizeToUniquePath _ANSI_ARGS_((Tcl_Interp *interp, 
		Tcl_Obj *pathPtr, int startAt, ClientData *clientDataPtr));
Tcl_Obj* TclFSMakePathRelative _ANSI_ARGS_((Tcl_Interp *interp, 
		Tcl_Obj *objPtr, Tcl_Obj *cwdPtr));
Tcl_Obj* TclFSInternalToNormalized _ANSI_ARGS_((
		Tcl_Filesystem *fromFilesystem, ClientData clientData,
		FilesystemRecord **fsRecPtrPtr));
int      TclFSEnsureEpochOk _ANSI_ARGS_((Tcl_Obj* pathObjPtr,
		Tcl_Filesystem **fsPtrPtr));
void     TclFSSetPathDetails _ANSI_ARGS_((Tcl_Obj *pathObjPtr, 
		FilesystemRecord *fsRecPtr, ClientData clientData ));
Tcl_Obj* TclFSNormalizeAbsolutePath _ANSI_ARGS_((Tcl_Interp* interp, 
		Tcl_Obj *pathPtr, ClientData *clientDataPtr));

/* 
 * Private shared variables for use by tclIOUtil.c and tclPathObj.c
 */
extern Tcl_Filesystem tclNativeFilesystem;
extern Tcl_ThreadDataKey tclFsDataKey;

/* 
 * Private shared functions for use by tclIOUtil.c and tclPathObj.c
 */
Tcl_PathType     TclFSGetPathType  _ANSI_ARGS_((Tcl_Obj *pathObjPtr, 
			    Tcl_Filesystem **filesystemPtrPtr, 
			    int *driveNameLengthPtr));
Tcl_PathType     TclGetPathType  _ANSI_ARGS_((Tcl_Obj *pathObjPtr, 
			    Tcl_Filesystem **filesystemPtrPtr, 
			    int *driveNameLengthPtr, Tcl_Obj **driveNameRef));
Tcl_FSPathInFilesystemProc TclNativePathInFilesystem;







>











|

|



|



|

|













|


|



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
 * time the corresponding epoch counter changes.
 */
typedef struct ThreadSpecificData {
    int initialized;
    int cwdPathEpoch;
    int filesystemEpoch;
    Tcl_Obj *cwdPathPtr;
    ClientData cwdClientData;
    FilesystemRecord *filesystemList;
} ThreadSpecificData;

/* 
 * The internal TclFS API provides routines for handling and
 * manipulating paths efficiently, taking direct advantage of
 * the "path" Tcl_Obj type.
 * 
 * These functions are not exported at all at present.
 */

int      TclFSCwdPointerEquals _ANSI_ARGS_((Tcl_Obj** pathPtrPtr));
int	 TclFSMakePathFromNormalized _ANSI_ARGS_((Tcl_Interp *interp, 
		Tcl_Obj *pathPtr, ClientData clientData));
int      TclFSNormalizeToUniquePath _ANSI_ARGS_((Tcl_Interp *interp, 
		Tcl_Obj *pathPtr, int startAt, ClientData *clientDataPtr));
Tcl_Obj* TclFSMakePathRelative _ANSI_ARGS_((Tcl_Interp *interp, 
		Tcl_Obj *pathPtr, Tcl_Obj *cwdPtr));
Tcl_Obj* TclFSInternalToNormalized _ANSI_ARGS_((
		Tcl_Filesystem *fromFilesystem, ClientData clientData,
		FilesystemRecord **fsRecPtrPtr));
int      TclFSEnsureEpochOk _ANSI_ARGS_((Tcl_Obj* pathPtr,
		Tcl_Filesystem **fsPtrPtr));
void     TclFSSetPathDetails _ANSI_ARGS_((Tcl_Obj *pathPtr, 
		FilesystemRecord *fsRecPtr, ClientData clientData ));
Tcl_Obj* TclFSNormalizeAbsolutePath _ANSI_ARGS_((Tcl_Interp* interp, 
		Tcl_Obj *pathPtr, ClientData *clientDataPtr));

/* 
 * Private shared variables for use by tclIOUtil.c and tclPathObj.c
 */
extern Tcl_Filesystem tclNativeFilesystem;
extern Tcl_ThreadDataKey tclFsDataKey;

/* 
 * Private shared functions for use by tclIOUtil.c and tclPathObj.c
 */
Tcl_PathType     TclFSGetPathType  _ANSI_ARGS_((Tcl_Obj *pathPtr, 
			    Tcl_Filesystem **filesystemPtrPtr, 
			    int *driveNameLengthPtr));
Tcl_PathType     TclGetPathType  _ANSI_ARGS_((Tcl_Obj *pathPtr, 
			    Tcl_Filesystem **filesystemPtrPtr, 
			    int *driveNameLengthPtr, Tcl_Obj **driveNameRef));
Tcl_FSPathInFilesystemProc TclNativePathInFilesystem;
Changes to generic/tclHash.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

17
18
19
20
21
22
23
/* 
 * tclHash.c --
 *
 *	Implementation of in-memory hash tables for Tcl and Tcl-based
 *	applications.
 *
 * Copyright (c) 1991-1993 The Regents of the University of California.
 * Copyright (c) 1994 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclHash.c,v 1.12.4.1 2003/06/27 15:10:10 dgp Exp $
 */

#include "tclInt.h"


/*
 * Prevent macros from clashing with function definitions.
 */

#if TCL_PRESERVE_BINARY_COMPATABILITY
#   undef Tcl_FindHashEntry












|



>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* 
 * tclHash.c --
 *
 *	Implementation of in-memory hash tables for Tcl and Tcl-based
 *	applications.
 *
 * Copyright (c) 1991-1993 The Regents of the University of California.
 * Copyright (c) 1994 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclHash.c,v 1.12.4.2 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * Prevent macros from clashing with function definitions.
 */

#if TCL_PRESERVE_BINARY_COMPATABILITY
#   undef Tcl_FindHashEntry
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
					 * TCL_CUSTOM_TYPE_KEYS,
					 * TCL_CUSTOM_PTR_KEYS,  or an
					 * integer >= 2. */
    Tcl_HashKeyType *typePtr;		/* Pointer to structure which defines
					 * the behaviour of this table. */
{
#if (TCL_SMALL_HASH_TABLE != 4) 
    panic("Tcl_InitCustomHashTable: TCL_SMALL_HASH_TABLE is %d, not 4\n",
	    TCL_SMALL_HASH_TABLE);
#endif
    
    tablePtr->buckets = tablePtr->staticBuckets;
    tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0;
    tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
    tablePtr->numBuckets = TCL_SMALL_HASH_TABLE;







|







189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
					 * TCL_CUSTOM_TYPE_KEYS,
					 * TCL_CUSTOM_PTR_KEYS,  or an
					 * integer >= 2. */
    Tcl_HashKeyType *typePtr;		/* Pointer to structure which defines
					 * the behaviour of this table. */
{
#if (TCL_SMALL_HASH_TABLE != 4) 
    Tcl_Panic("Tcl_InitCustomHashTable: TCL_SMALL_HASH_TABLE is %d, not 4\n",
	    TCL_SMALL_HASH_TABLE);
#endif
    
    tablePtr->buckets = tablePtr->staticBuckets;
    tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0;
    tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
    tablePtr->numBuckets = TCL_SMALL_HASH_TABLE;
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
#endif
    
    if (*bucketPtr == entryPtr) {
	*bucketPtr = entryPtr->nextPtr;
    } else {
	for (prevPtr = *bucketPtr; ; prevPtr = prevPtr->nextPtr) {
	    if (prevPtr == NULL) {
		panic("malformed bucket chain in Tcl_DeleteHashEntry");
	    }
	    if (prevPtr->nextPtr == entryPtr) {
		prevPtr->nextPtr = entryPtr->nextPtr;
		break;
	    }
	}
    }







|







544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
#endif
    
    if (*bucketPtr == entryPtr) {
	*bucketPtr = entryPtr->nextPtr;
    } else {
	for (prevPtr = *bucketPtr; ; prevPtr = prevPtr->nextPtr) {
	    if (prevPtr == NULL) {
		Tcl_Panic("malformed bucket chain in Tcl_DeleteHashEntry");
	    }
	    if (prevPtr->nextPtr == entryPtr) {
		prevPtr->nextPtr = entryPtr->nextPtr;
		break;
	    }
	}
    }
622
623
624
625
626
627
628



629

630
631
632
633
634
635
636
    }

    /*
     * Free up the bucket array, if it was dynamically allocated.
     */

    if (tablePtr->buckets != tablePtr->staticBuckets) {



	ckfree((char *) tablePtr->buckets);

    }

    /*
     * Arrange for panics if the table is used again without
     * re-initialization.
     */








>
>
>
|
>







623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
    }

    /*
     * Free up the bucket array, if it was dynamically allocated.
     */

    if (tablePtr->buckets != tablePtr->staticBuckets) {
	if (typePtr->flags & TCL_HASH_KEY_SYSTEM_HASH) {
	    TclpSysFree((char *) tablePtr->buckets);
	} else {
	    ckfree((char *) tablePtr->buckets);
	}
    }

    /*
     * Arrange for panics if the table is used again without
     * re-initialization.
     */

741
742
743
744
745
746
747




















748
749
750
751
752
753
754
    Tcl_HashTable *tablePtr;		/* Table for which to produce stats. */
{
#define NUM_COUNTERS 10
    int count[NUM_COUNTERS], overflow, i, j;
    double average, tmp;
    register Tcl_HashEntry *hPtr;
    char *result, *p;





















    /*
     * Compute a histogram of bucket usage.
     */

    for (i = 0; i < NUM_COUNTERS; i++) {
	count[i] = 0;







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







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
    Tcl_HashTable *tablePtr;		/* Table for which to produce stats. */
{
#define NUM_COUNTERS 10
    int count[NUM_COUNTERS], overflow, i, j;
    double average, tmp;
    register Tcl_HashEntry *hPtr;
    char *result, *p;
    Tcl_HashKeyType *typePtr;

#if TCL_PRESERVE_BINARY_COMPATABILITY
    if (tablePtr->keyType == TCL_STRING_KEYS) {
	typePtr = &tclStringHashKeyType;
    } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
	typePtr = &tclOneWordHashKeyType;
    } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
	       || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
	typePtr = tablePtr->typePtr;
    } else {
	typePtr = &tclArrayHashKeyType;
    }
#else
    typePtr = tablePtr->typePtr;
    if (typePtr == NULL) {
	Tcl_Panic("called Tcl_HashStats on deleted table");
	return NULL;
    }
#endif

    /*
     * Compute a histogram of bucket usage.
     */

    for (i = 0; i < NUM_COUNTERS; i++) {
	count[i] = 0;
770
771
772
773
774
775
776
777


778

779
780
781
782
783
784
785
	    average += (tmp+1.0)*(tmp/tablePtr->numEntries)/2.0;
	}
    }

    /*
     * Print out the histogram and a few other pieces of information.
     */



    result = (char *) ckalloc((unsigned) ((NUM_COUNTERS*60) + 300));

    sprintf(result, "%d entries in table, %d buckets\n",
	    tablePtr->numEntries, tablePtr->numBuckets);
    p = result + strlen(result);
    for (i = 0; i < NUM_COUNTERS; i++) {
	sprintf(p, "number of buckets with %d entries: %d\n",
		i, count[i]);
	p += strlen(p);







|
>
>
|
>







795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
	    average += (tmp+1.0)*(tmp/tablePtr->numEntries)/2.0;
	}
    }

    /*
     * Print out the histogram and a few other pieces of information.
     */
    if (typePtr->flags & TCL_HASH_KEY_SYSTEM_HASH) {
	result = (char *) TclpSysAlloc((unsigned) (NUM_COUNTERS*60) + 300, 0);
    } else {
	result = (char *) ckalloc((unsigned) (NUM_COUNTERS*60) + 300);
    }
    sprintf(result, "%d entries in table, %d buckets\n",
	    tablePtr->numEntries, tablePtr->numBuckets);
    p = result + strlen(result);
    for (i = 0; i < NUM_COUNTERS; i++) {
	sprintf(p, "number of buckets with %d entries: %d\n",
		i, count[i]);
	p += strlen(p);
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
 *
 * BogusFind --
 *
 *	This procedure is invoked when an Tcl_FindHashEntry is called
 *	on a table that has been deleted.
 *
 * Results:
 *	If panic returns (which it shouldn't) this procedure returns
 *	NULL.
 *
 * Side effects:
 *	Generates a panic.
 *
 *----------------------------------------------------------------------
 */

	/* ARGSUSED */
static Tcl_HashEntry *
BogusFind(tablePtr, key)
    Tcl_HashTable *tablePtr;	/* Table in which to lookup entry. */
    CONST char *key;		/* Key to use to find matching entry. */
{
    panic("called Tcl_FindHashEntry on deleted table");
    return NULL;
}

/*
 *----------------------------------------------------------------------
 *
 * BogusCreate --







|














|







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
 *
 * BogusFind --
 *
 *	This procedure is invoked when an Tcl_FindHashEntry is called
 *	on a table that has been deleted.
 *
 * Results:
 *	If Tcl_Panic returns (which it shouldn't) this procedure returns
 *	NULL.
 *
 * Side effects:
 *	Generates a panic.
 *
 *----------------------------------------------------------------------
 */

	/* ARGSUSED */
static Tcl_HashEntry *
BogusFind(tablePtr, key)
    Tcl_HashTable *tablePtr;	/* Table in which to lookup entry. */
    CONST char *key;		/* Key to use to find matching entry. */
{
    Tcl_Panic("called Tcl_FindHashEntry on deleted table");
    return NULL;
}

/*
 *----------------------------------------------------------------------
 *
 * BogusCreate --
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
BogusCreate(tablePtr, key, newPtr)
    Tcl_HashTable *tablePtr;	/* Table in which to lookup entry. */
    CONST char *key;		/* Key to use to find or create matching
				 * entry. */
    int *newPtr;		/* Store info here telling whether a new
				 * entry was created. */
{
    panic("called Tcl_CreateHashEntry on deleted table");
    return NULL;
}
#endif

/*
 *----------------------------------------------------------------------
 *







|







1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
BogusCreate(tablePtr, key, newPtr)
    Tcl_HashTable *tablePtr;	/* Table in which to lookup entry. */
    CONST char *key;		/* Key to use to find or create matching
				 * entry. */
    int *newPtr;		/* Store info here telling whether a new
				 * entry was created. */
{
    Tcl_Panic("called Tcl_CreateHashEntry on deleted table");
    return NULL;
}
#endif

/*
 *----------------------------------------------------------------------
 *
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
    int oldSize, count, index;
    Tcl_HashEntry **oldBuckets;
    register Tcl_HashEntry **oldChainPtr, **newChainPtr;
    register Tcl_HashEntry *hPtr;
    Tcl_HashKeyType *typePtr;
    VOID *key;

    oldSize = tablePtr->numBuckets;
    oldBuckets = tablePtr->buckets;

    /*
     * Allocate and initialize the new bucket array, and set up
     * hashing constants for new array size.
     */

    tablePtr->numBuckets *= 4;
    tablePtr->buckets = (Tcl_HashEntry **) ckalloc((unsigned)
	    (tablePtr->numBuckets * sizeof(Tcl_HashEntry *)));
    for (count = tablePtr->numBuckets, newChainPtr = tablePtr->buckets;
	    count > 0; count--, newChainPtr++) {
	*newChainPtr = NULL;
    }
    tablePtr->rebuildSize *= 4;
    tablePtr->downShift -= 2;
    tablePtr->mask = (tablePtr->mask << 2) + 3;

#if TCL_PRESERVE_BINARY_COMPATABILITY
    if (tablePtr->keyType == TCL_STRING_KEYS) {
	typePtr = &tclStringHashKeyType;
    } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
	typePtr = &tclOneWordHashKeyType;
    } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
	       || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
	typePtr = tablePtr->typePtr;
    } else {
	typePtr = &tclArrayHashKeyType;
    }
#else
    typePtr = tablePtr->typePtr;
#endif

























    /*
     * Rehash all of the existing entries into the new bucket array.
     */

    for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) {
	for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) {
	    *oldChainPtr = hPtr->nextPtr;







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















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







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
    int oldSize, count, index;
    Tcl_HashEntry **oldBuckets;
    register Tcl_HashEntry **oldChainPtr, **newChainPtr;
    register Tcl_HashEntry *hPtr;
    Tcl_HashKeyType *typePtr;
    VOID *key;




















#if TCL_PRESERVE_BINARY_COMPATABILITY
    if (tablePtr->keyType == TCL_STRING_KEYS) {
	typePtr = &tclStringHashKeyType;
    } else if (tablePtr->keyType == TCL_ONE_WORD_KEYS) {
	typePtr = &tclOneWordHashKeyType;
    } else if (tablePtr->keyType == TCL_CUSTOM_TYPE_KEYS
	       || tablePtr->keyType == TCL_CUSTOM_PTR_KEYS) {
	typePtr = tablePtr->typePtr;
    } else {
	typePtr = &tclArrayHashKeyType;
    }
#else
    typePtr = tablePtr->typePtr;
#endif

    oldSize = tablePtr->numBuckets;
    oldBuckets = tablePtr->buckets;

    /*
     * Allocate and initialize the new bucket array, and set up
     * hashing constants for new array size.
     */

    tablePtr->numBuckets *= 4;
    if (typePtr->flags & TCL_HASH_KEY_SYSTEM_HASH) {
	tablePtr->buckets = (Tcl_HashEntry **) TclpSysAlloc((unsigned)
		(tablePtr->numBuckets * sizeof(Tcl_HashEntry *)), 0);
    } else {
	tablePtr->buckets = (Tcl_HashEntry **) ckalloc((unsigned)
		(tablePtr->numBuckets * sizeof(Tcl_HashEntry *)));
    }
    for (count = tablePtr->numBuckets, newChainPtr = tablePtr->buckets;
	    count > 0; count--, newChainPtr++) {
	*newChainPtr = NULL;
    }
    tablePtr->rebuildSize *= 4;
    tablePtr->downShift -= 2;
    tablePtr->mask = (tablePtr->mask << 2) + 3;

    /*
     * Rehash all of the existing entries into the new bucket array.
     */

    for (oldChainPtr = oldBuckets; oldSize > 0; oldSize--, oldChainPtr++) {
	for (hPtr = *oldChainPtr; hPtr != NULL; hPtr = *oldChainPtr) {
	    *oldChainPtr = hPtr->nextPtr;
1196
1197
1198
1199
1200
1201
1202



1203
1204
1205

    }

    /*
     * Free up the old bucket array, if it was dynamically allocated.
     */

    if (oldBuckets != tablePtr->staticBuckets) {



	ckfree((char *) oldBuckets);
    }
}








>
>
>
|
|
|
>
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
    }

    /*
     * Free up the old bucket array, if it was dynamically allocated.
     */

    if (oldBuckets != tablePtr->staticBuckets) {
	if (typePtr->flags & TCL_HASH_KEY_SYSTEM_HASH) {
	    TclpSysFree((char *) oldBuckets);
	} else {
	    ckfree((char *) oldBuckets);
	}
    }
}
Changes to generic/tclIO.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclIO.c --
 *
 *	This file provides the generic portions (those that are the same on
 *	all platforms and for all channel types) of Tcl's IO facilities.
 *
 * Copyright (c) 1998-2000 Ajuba Solutions
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclIO.c,v 1.68 2003/04/22 23:20:41 andreas_kupries Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include "tclIO.h"
#include <assert.h>













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclIO.c --
 *
 *	This file provides the generic portions (those that are the same on
 *	all platforms and for all channel types) of Tcl's IO facilities.
 *
 * Copyright (c) 1998-2000 Ajuba Solutions
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclIO.c,v 1.68.2.1 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include "tclIO.h"
#include <assert.h>

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
     * management of the channel list easier because no manipulation is
     * necessary during (un)stack operation.
     */
    chanPtr = ((Channel *) chan)->state->bottomChanPtr;
    statePtr = chanPtr->state;

    if (statePtr->channelName == (CONST char *) NULL) {
        panic("Tcl_RegisterChannel: channel without name");
    }
    if (interp != (Tcl_Interp *) NULL) {
        hTblPtr = GetChannelTable(interp);
        hPtr = Tcl_CreateHashEntry(hTblPtr, statePtr->channelName, &new);
        if (new == 0) {
            if (chan == (Tcl_Channel) Tcl_GetHashValue(hPtr)) {
                return;
            }

	    panic("Tcl_RegisterChannel: duplicate channel names");
        }
        Tcl_SetHashValue(hPtr, (ClientData) chanPtr);
    }
    statePtr->refCount++;
}

/*







|









|







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
     * management of the channel list easier because no manipulation is
     * necessary during (un)stack operation.
     */
    chanPtr = ((Channel *) chan)->state->bottomChanPtr;
    statePtr = chanPtr->state;

    if (statePtr->channelName == (CONST char *) NULL) {
        Tcl_Panic("Tcl_RegisterChannel: channel without name");
    }
    if (interp != (Tcl_Interp *) NULL) {
        hTblPtr = GetChannelTable(interp);
        hPtr = Tcl_CreateHashEntry(hTblPtr, statePtr->channelName, &new);
        if (new == 0) {
            if (chan == (Tcl_Channel) Tcl_GetHashValue(hPtr)) {
                return;
            }

	    Tcl_Panic("Tcl_RegisterChannel: duplicate channel names");
        }
        Tcl_SetHashValue(hPtr, (ClientData) chanPtr);
    }
    statePtr->refCount++;
}

/*
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
     */

    if (chanName != (char *) NULL) {
	char *tmp = ckalloc((unsigned) (strlen(chanName) + 1));
        statePtr->channelName = tmp;
        strcpy(tmp, chanName);
    } else {
        panic("Tcl_CreateChannel: NULL channel name");
    }

    statePtr->flags		= mask;

    /*
     * Set the channel to system default encoding.
     */







|







1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
     */

    if (chanName != (char *) NULL) {
	char *tmp = ckalloc((unsigned) (strlen(chanName) + 1));
        statePtr->channelName = tmp;
        strcpy(tmp, chanName);
    } else {
        Tcl_Panic("Tcl_CreateChannel: NULL channel name");
    }

    statePtr->flags		= mask;

    /*
     * Set the channel to system default encoding.
     */
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
    
    /*
     * The caller guarantees that there are no more buffers
     * queued for output.
     */

    if (statePtr->outQueueHead != (ChannelBuffer *) NULL) {
        panic("TclFlush, closed channel: queued output left");
    }

    /*
     * If the EOF character is set in the channel, append that to the
     * output device.
     */








|







2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
    
    /*
     * The caller guarantees that there are no more buffers
     * queued for output.
     */

    if (statePtr->outQueueHead != (ChannelBuffer *) NULL) {
        Tcl_Panic("TclFlush, closed channel: queued output left");
    }

    /*
     * If the EOF character is set in the channel, append that to the
     * output device.
     */

2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
    } else {
        for (prevCSPtr = tsdPtr->firstCSPtr;
	     prevCSPtr && (prevCSPtr->nextCSPtr != statePtr);
	     prevCSPtr = prevCSPtr->nextCSPtr) {
            /* Empty loop body. */
        }
        if (prevCSPtr == (ChannelState *) NULL) {
            panic("FlushChannel: damaged channel list");
        }
        prevCSPtr->nextCSPtr = statePtr->nextCSPtr;
    }

    statePtr->nextCSPtr = (ChannelState *) NULL;

    TclpCutFileChannel(chan);







|







2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
    } else {
        for (prevCSPtr = tsdPtr->firstCSPtr;
	     prevCSPtr && (prevCSPtr->nextCSPtr != statePtr);
	     prevCSPtr = prevCSPtr->nextCSPtr) {
            /* Empty loop body. */
        }
        if (prevCSPtr == (ChannelState *) NULL) {
            Tcl_Panic("FlushChannel: damaged channel list");
        }
        prevCSPtr->nextCSPtr = statePtr->nextCSPtr;
    }

    statePtr->nextCSPtr = (ChannelState *) NULL;

    TclpCutFileChannel(chan);
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
                                         * not be referenced in any
                                         * interpreter. */
{
    ThreadSpecificData	*tsdPtr = TCL_TSD_INIT(&dataKey);
    ChannelState	*statePtr = ((Channel *) chan)->state;

    if (statePtr->nextCSPtr != (ChannelState *) NULL) {
        panic("Tcl_SpliceChannel: trying to add channel used in different list");
    }

    statePtr->nextCSPtr	= tsdPtr->firstCSPtr;
    tsdPtr->firstCSPtr	= statePtr;

    /*
     * TIP #10. Mark the current thread as the new one managing this







|







2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
                                         * not be referenced in any
                                         * interpreter. */
{
    ThreadSpecificData	*tsdPtr = TCL_TSD_INIT(&dataKey);
    ChannelState	*statePtr = ((Channel *) chan)->state;

    if (statePtr->nextCSPtr != (ChannelState *) NULL) {
        Tcl_Panic("Tcl_SpliceChannel: trying to add channel used in different list");
    }

    statePtr->nextCSPtr	= tsdPtr->firstCSPtr;
    tsdPtr->firstCSPtr	= statePtr;

    /*
     * TIP #10. Mark the current thread as the new one managing this
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
     */

    chanPtr	= (Channel *) chan;
    statePtr	= chanPtr->state;
    chanPtr	= statePtr->topChanPtr;

    if (statePtr->refCount > 0) {
        panic("called Tcl_Close on channel with refCount > 0");
    }

    /*
     * When the channel has an escape sequence driven encoding such as
     * iso2022, the terminated escape sequence must write to the buffer.
     */
    if ((statePtr->encoding != NULL) && (statePtr->curOutPtr != NULL)







|







2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
     */

    chanPtr	= (Channel *) chan;
    statePtr	= chanPtr->state;
    chanPtr	= statePtr->topChanPtr;

    if (statePtr->refCount > 0) {
        Tcl_Panic("called Tcl_Close on channel with refCount > 0");
    }

    /*
     * When the channel has an escape sequence driven encoding such as
     * iso2022, the terminated escape sequence must write to the buffer.
     */
    if ((statePtr->encoding != NULL) && (statePtr->curOutPtr != NULL)
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
    if (statePtr->flags & CHANNEL_STICKY_EOF) {
	goto done;
    }
    statePtr->flags &= (~(CHANNEL_BLOCKED | CHANNEL_EOF));

    bufPtr = AllocChannelBuffer(len);
    for (i = 0; i < len; i++) {
        bufPtr->buf[i] = str[i];
    }
    bufPtr->nextAdded += len;

    if (statePtr->inQueueHead == (ChannelBuffer *) NULL) {
        bufPtr->nextPtr = (ChannelBuffer *) NULL;
        statePtr->inQueueHead = bufPtr;
        statePtr->inQueueTail = bufPtr;
    } else if (atEnd) {
        bufPtr->nextPtr = (ChannelBuffer *) NULL;







|

<







5050
5051
5052
5053
5054
5055
5056
5057
5058

5059
5060
5061
5062
5063
5064
5065
    if (statePtr->flags & CHANNEL_STICKY_EOF) {
	goto done;
    }
    statePtr->flags &= (~(CHANNEL_BLOCKED | CHANNEL_EOF));

    bufPtr = AllocChannelBuffer(len);
    for (i = 0; i < len; i++) {
        bufPtr->buf[bufPtr->nextAdded++] = str[i];
    }


    if (statePtr->inQueueHead == (ChannelBuffer *) NULL) {
        bufPtr->nextPtr = (ChannelBuffer *) NULL;
        statePtr->inQueueHead = bufPtr;
        statePtr->inQueueTail = bufPtr;
    } else if (atEnd) {
        bufPtr->nextPtr = (ChannelBuffer *) NULL;
6062
6063
6064
6065
6066
6067
6068
6069
6070
6071
6072
6073
6074
6075
6076
	Tcl_DStringAppend(&ds, genericopt, -1);
	if (optionList && (*optionList)) {
	    Tcl_DStringAppend(&ds, " ", 1);
	    Tcl_DStringAppend(&ds, optionList, -1);
	}
	if (Tcl_SplitList(interp, Tcl_DStringValue(&ds), 
		&argc, &argv) != TCL_OK) {
	    panic("malformed option list in channel driver");
	}
	Tcl_ResetResult(interp);
	Tcl_AppendResult(interp, "bad option \"", optionName, 
		"\": should be one of ", (char *) NULL);
	argc--;
	for (i = 0; i < argc; i++) {
	    Tcl_AppendResult(interp, "-", argv[i], ", ", (char *) NULL);







|







6061
6062
6063
6064
6065
6066
6067
6068
6069
6070
6071
6072
6073
6074
6075
	Tcl_DStringAppend(&ds, genericopt, -1);
	if (optionList && (*optionList)) {
	    Tcl_DStringAppend(&ds, " ", 1);
	    Tcl_DStringAppend(&ds, optionList, -1);
	}
	if (Tcl_SplitList(interp, Tcl_DStringValue(&ds), 
		&argc, &argv) != TCL_OK) {
	    Tcl_Panic("malformed option list in channel driver");
	}
	Tcl_ResetResult(interp);
	Tcl_AppendResult(interp, "bad option \"", optionName, 
		"\": should be one of ", (char *) NULL);
	argc--;
	for (i = 0; i < argc; i++) {
	    Tcl_AppendResult(interp, "-", argv[i], ", ", (char *) NULL);
8079
8080
8081
8082
8083
8084
8085
8086
8087
8088
8089
8090
8091
8092
8093
		    statePtr->flags &= ~INPUT_SAW_CR;
		}
	    }
	    copied = dst - result;
            break;
	}
        default: {
            panic("unknown eol translation mode");
	}
    }

    /*
     * If an in-stream EOF character is set for this channel, check that
     * the input we copied so far does not contain the EOF char.  If it does,
     * copy only up to and excluding that character.







|







8078
8079
8080
8081
8082
8083
8084
8085
8086
8087
8088
8089
8090
8091
8092
		    statePtr->flags &= ~INPUT_SAW_CR;
		}
	    }
	    copied = dst - result;
            break;
	}
        default: {
            Tcl_Panic("unknown eol translation mode");
	}
    }

    /*
     * If an in-stream EOF character is set for this channel, check that
     * the input we copied so far does not contain the EOF char.  If it does,
     * copy only up to and excluding that character.
8330
8331
8332
8333
8334
8335
8336
8337
8338
8339
8340
8341
8342
8343
8344
8345
8346
                        }
                    } else {
                        *dPtr = *sPtr;
                    }
                }
                break;
            case TCL_TRANSLATE_AUTO:
                panic("Tcl_Write: AUTO output translation mode not supported");
            default:
                panic("Tcl_Write: unknown output translation mode");
        }

        /*
         * The current buffer is ready for output if it is full, or if it
         * contains a newline and this channel is line-buffered, or if it
         * contains any output and this channel is unbuffered.
         */







|

|







8329
8330
8331
8332
8333
8334
8335
8336
8337
8338
8339
8340
8341
8342
8343
8344
8345
                        }
                    } else {
                        *dPtr = *sPtr;
                    }
                }
                break;
            case TCL_TRANSLATE_AUTO:
                Tcl_Panic("Tcl_Write: AUTO output translation mode not supported");
            default:
                Tcl_Panic("Tcl_Write: unknown output translation mode");
        }

        /*
         * The current buffer is ready for output if it is full, or if it
         * contains a newline and this channel is line-buffered, or if it
         * contains any output and this channel is unbuffered.
         */
Changes to generic/tclIOCmd.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 
 * tclIOCmd.c --
 *
 *	Contains the definitions of most of the Tcl commands relating to IO.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclIOCmd.c,v 1.15 2002/02/15 14:28:49 dkf Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * Callback structure for accept callback in a TCP server.










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 
 * tclIOCmd.c --
 *
 *	Contains the definitions of most of the Tcl commands relating to IO.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclIOCmd.c,v 1.15.4.1 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * Callback structure for accept callback in a TCP server.
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
		case O_WRONLY:
		    flags |= TCL_STDIN;
		    break;
		case O_RDWR:
		    flags |= (TCL_STDIN | TCL_STDOUT);
		    break;
		default:
		    panic("Tcl_OpenCmd: invalid mode value");
		    break;
	    }
	    chan = Tcl_OpenCommandChannel(interp, cmdObjc, cmdArgv, flags);
	}
        ckfree((char *) cmdArgv);
#endif
    }







|







993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
		case O_WRONLY:
		    flags |= TCL_STDIN;
		    break;
		case O_RDWR:
		    flags |= (TCL_STDIN | TCL_STDOUT);
		    break;
		default:
		    Tcl_Panic("Tcl_OpenCmd: invalid mode value");
		    break;
	    }
	    chan = Tcl_OpenCommandChannel(interp, cmdObjc, cmdArgv, flags);
	}
        ckfree((char *) cmdArgv);
#endif
    }
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
        hTblPtr = (Tcl_HashTable *) ckalloc((unsigned) sizeof(Tcl_HashTable));
        Tcl_InitHashTable(hTblPtr, TCL_ONE_WORD_KEYS);
        (void) Tcl_SetAssocData(interp, "tclTCPAcceptCallbacks",
                TcpAcceptCallbacksDeleteProc, (ClientData) hTblPtr);
    }
    hPtr = Tcl_CreateHashEntry(hTblPtr, (char *) acceptCallbackPtr, &new);
    if (!new) {
        panic("RegisterTcpServerCleanup: damaged accept record table");
    }
    Tcl_SetHashValue(hPtr, (ClientData) acceptCallbackPtr);
}

/*
 *----------------------------------------------------------------------
 *







|







1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
        hTblPtr = (Tcl_HashTable *) ckalloc((unsigned) sizeof(Tcl_HashTable));
        Tcl_InitHashTable(hTblPtr, TCL_ONE_WORD_KEYS);
        (void) Tcl_SetAssocData(interp, "tclTCPAcceptCallbacks",
                TcpAcceptCallbacksDeleteProc, (ClientData) hTblPtr);
    }
    hPtr = Tcl_CreateHashEntry(hTblPtr, (char *) acceptCallbackPtr, &new);
    if (!new) {
        Tcl_Panic("RegisterTcpServerCleanup: damaged accept record table");
    }
    Tcl_SetHashValue(hPtr, (ClientData) acceptCallbackPtr);
}

/*
 *----------------------------------------------------------------------
 *
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
                            (char *) NULL);
		    return TCL_ERROR;
		}
                script = Tcl_GetString(objv[a]);
		break;
	    }
	    default: {
		panic("Tcl_SocketObjCmd: bad option index to SocketOptions");
	    }
	}
    }
    if (server) {
        host = myaddr;		/* NULL implies INADDR_ANY */
	if (myport != 0) {
	    Tcl_AppendResult(interp, "Option -myport is not valid for servers",







|







1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
                            (char *) NULL);
		    return TCL_ERROR;
		}
                script = Tcl_GetString(objv[a]);
		break;
	    }
	    default: {
		Tcl_Panic("Tcl_SocketObjCmd: bad option index to SocketOptions");
	    }
	}
    }
    if (server) {
        host = myaddr;		/* NULL implies INADDR_ANY */
	if (myport != 0) {
	    Tcl_AppendResult(interp, "Option -myport is not valid for servers",
Changes to generic/tclIOUtil.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
 *
 * Copyright (c) 1991-1994 The Regents of the University of California.
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclIOUtil.c,v 1.81.2.4 2003/10/16 02:28:02 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#ifdef MAC_TCL
#include "tclMacInt.h"
#endif
#ifdef __WIN32__
/* for tclWinProcs->useWide */
#include "tclWinInt.h"
#endif
#include "tclFileSystem.h"

/*
 * Prototypes for procedures defined later in this file.
 */

static FilesystemRecord* FsGetFirstFilesystem _ANSI_ARGS_((void));
static void FsThrExitProc             _ANSI_ARGS_((ClientData cd));
static Tcl_Obj* FsListMounts          _ANSI_ARGS_((Tcl_Obj *pathPtr, 
						   CONST char *pattern));
static Tcl_Obj* FsAddMountsToGlobResult  _ANSI_ARGS_((Tcl_Obj *result, 
	   Tcl_Obj *pathPtr, CONST char *pattern, Tcl_GlobTypeData *types));



    
#ifdef TCL_THREADS
static void FsRecacheFilesystemList(void);
#endif

/* 
 * These form part of the native filesystem support.  They are needed
 * here because we have a few native filesystem functions (which are







|

















|
|
|
|
|
|
>
>
>
|







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
 *
 * Copyright (c) 1991-1994 The Regents of the University of California.
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclIOUtil.c,v 1.81.2.5 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#ifdef MAC_TCL
#include "tclMacInt.h"
#endif
#ifdef __WIN32__
/* for tclWinProcs->useWide */
#include "tclWinInt.h"
#endif
#include "tclFileSystem.h"

/*
 * Prototypes for procedures defined later in this file.
 */

static FilesystemRecord*   FsGetFirstFilesystem _ANSI_ARGS_((void));
static void                FsThrExitProc _ANSI_ARGS_((ClientData cd));
static Tcl_Obj*            FsListMounts _ANSI_ARGS_((Tcl_Obj *pathPtr, 
					   CONST char *pattern));
static Tcl_Obj*            FsAddMountsToGlobResult  _ANSI_ARGS_((Tcl_Obj *result, 
	                                   Tcl_Obj *pathPtr, CONST char *pattern, 
					   Tcl_GlobTypeData *types));
static void                FsUpdateCwd _ANSI_ARGS_((Tcl_Obj *cwdObj, 
					   ClientData clientData));

#ifdef TCL_THREADS
static void FsRecacheFilesystemList(void);
#endif

/* 
 * These form part of the native filesystem support.  They are needed
 * here because we have a few native filesystem functions (which are
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
 * which ensure correct and complete virtual filesystem support.
 * 
 * We cannot make all of these static, since some of them
 * are implemented in the platform-specific directories.
 */
static Tcl_FSFilesystemSeparatorProc NativeFilesystemSeparator;
static Tcl_FSFreeInternalRepProc NativeFreeInternalRep;
Tcl_FSDupInternalRepProc TclNativeDupInternalRep;
static Tcl_FSCreateInternalRepProc NativeCreateNativeRep;
static Tcl_FSFileAttrStringsProc NativeFileAttrStrings;
static Tcl_FSFileAttrsGetProc NativeFileAttrsGet;
static Tcl_FSFileAttrsSetProc NativeFileAttrsSet;

/* 
 * The only reason these functions are not static is that they
 * are either called by code in the native (win/unix/mac) directories
 * or they are actually implemented in those directories.  They
 * should simply not be called by code outside Tcl's native
 * filesystem core.  i.e. they should be considered 'static' to
 * Tcl's filesystem code (if we ever built the native filesystem
 * support into a separate code library, this could actually be
 * enforced).
 */
Tcl_FSFilesystemPathTypeProc TclpFilesystemPathType;
Tcl_FSInternalToNormalizedProc TclpNativeToNormalized;
Tcl_FSStatProc TclpObjStat;
Tcl_FSAccessProc TclpObjAccess;	    
Tcl_FSMatchInDirectoryProc TclpMatchInDirectory;  
Tcl_FSGetCwdProc TclpObjGetCwd;     
Tcl_FSChdirProc TclpObjChdir;	    
Tcl_FSLstatProc TclpObjLstat;	    
Tcl_FSCopyFileProc TclpObjCopyFile; 
Tcl_FSDeleteFileProc TclpObjDeleteFile;	    
Tcl_FSRenameFileProc TclpObjRenameFile;	    
Tcl_FSCreateDirectoryProc TclpObjCreateDirectory;	    
Tcl_FSCopyDirectoryProc TclpObjCopyDirectory;	    







<




















<







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
 * which ensure correct and complete virtual filesystem support.
 * 
 * We cannot make all of these static, since some of them
 * are implemented in the platform-specific directories.
 */
static Tcl_FSFilesystemSeparatorProc NativeFilesystemSeparator;
static Tcl_FSFreeInternalRepProc NativeFreeInternalRep;

static Tcl_FSCreateInternalRepProc NativeCreateNativeRep;
static Tcl_FSFileAttrStringsProc NativeFileAttrStrings;
static Tcl_FSFileAttrsGetProc NativeFileAttrsGet;
static Tcl_FSFileAttrsSetProc NativeFileAttrsSet;

/* 
 * The only reason these functions are not static is that they
 * are either called by code in the native (win/unix/mac) directories
 * or they are actually implemented in those directories.  They
 * should simply not be called by code outside Tcl's native
 * filesystem core.  i.e. they should be considered 'static' to
 * Tcl's filesystem code (if we ever built the native filesystem
 * support into a separate code library, this could actually be
 * enforced).
 */
Tcl_FSFilesystemPathTypeProc TclpFilesystemPathType;
Tcl_FSInternalToNormalizedProc TclpNativeToNormalized;
Tcl_FSStatProc TclpObjStat;
Tcl_FSAccessProc TclpObjAccess;	    
Tcl_FSMatchInDirectoryProc TclpMatchInDirectory;  

Tcl_FSChdirProc TclpObjChdir;	    
Tcl_FSLstatProc TclpObjLstat;	    
Tcl_FSCopyFileProc TclpObjCopyFile; 
Tcl_FSDeleteFileProc TclpObjDeleteFile;	    
Tcl_FSRenameFileProc TclpObjRenameFile;	    
Tcl_FSCreateDirectoryProc TclpObjCreateDirectory;	    
Tcl_FSCopyDirectoryProc TclpObjCopyDirectory;	    
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
 * helper functions of them).  Anything which is not part of this
 * 'native filesystem implementation' should not be delving inside
 * here!
 */
Tcl_Filesystem tclNativeFilesystem = {
    "native",
    sizeof(Tcl_Filesystem),
    TCL_FILESYSTEM_VERSION_1,
    &TclNativePathInFilesystem,
    &TclNativeDupInternalRep,
    &NativeFreeInternalRep,
    &TclpNativeToNormalized,
    &NativeCreateNativeRep,
    &TclpObjNormalizePath,
    &TclpFilesystemPathType,







|







339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
 * helper functions of them).  Anything which is not part of this
 * 'native filesystem implementation' should not be delving inside
 * here!
 */
Tcl_Filesystem tclNativeFilesystem = {
    "native",
    sizeof(Tcl_Filesystem),
    TCL_FILESYSTEM_VERSION_2,
    &TclNativePathInFilesystem,
    &TclNativeDupInternalRep,
    &NativeFreeInternalRep,
    &TclpNativeToNormalized,
    &NativeCreateNativeRep,
    &TclpObjNormalizePath,
    &TclpFilesystemPathType,
369
370
371
372
373
374
375

376
377
378
379
380
381
382
383
    &TclpObjRemoveDirectory, 
    &TclpObjDeleteFile,
    &TclpObjCopyFile,
    &TclpObjRenameFile,
    &TclpObjCopyDirectory, 
    &TclpObjLstat,
    &TclpDlopen,

    &TclpObjGetCwd,
    &TclpObjChdir
};

/* 
 * Define the tail of the linked list.  Note that for unconventional
 * uses of Tcl without a native filesystem, we may in the future wish
 * to modify the current approach of hard-coding the native filesystem







>
|







370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
    &TclpObjRemoveDirectory, 
    &TclpObjDeleteFile,
    &TclpObjCopyFile,
    &TclpObjRenameFile,
    &TclpObjCopyDirectory, 
    &TclpObjLstat,
    &TclpDlopen,
    /* Needs a cast since we're using version_2 */
    (Tcl_FSGetCwdProc*)&TclpGetNativeCwd,
    &TclpObjChdir
};

/* 
 * Define the tail of the linked list.  Note that for unconventional
 * uses of Tcl without a native filesystem, we may in the future wish
 * to modify the current approach of hard-coding the native filesystem
411
412
413
414
415
416
417

418
419
420
421
422
423
424
TCL_DECLARE_MUTEX(filesystemMutex)

/* 
 * Used to implement Tcl_FSGetCwd in a file-system independent way.
 */
static Tcl_Obj* cwdPathPtr = NULL;
static int cwdPathEpoch = 0;

TCL_DECLARE_MUTEX(cwdMutex)

Tcl_ThreadDataKey tclFsDataKey;

/* 
 * Declare fallback support function and 
 * information for Tcl_FSLoadFile 







>







413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
TCL_DECLARE_MUTEX(filesystemMutex)

/* 
 * Used to implement Tcl_FSGetCwd in a file-system independent way.
 */
static Tcl_Obj* cwdPathPtr = NULL;
static int cwdPathEpoch = 0;
static ClientData cwdClientData = NULL;
TCL_DECLARE_MUTEX(cwdMutex)

Tcl_ThreadDataKey tclFsDataKey;

/* 
 * Declare fallback support function and 
 * information for Tcl_FSLoadFile 
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
    ThreadSpecificData *tsdPtr = (ThreadSpecificData*)cd;
    FilesystemRecord *fsRecPtr = NULL, *tmpFsRecPtr = NULL;

    /* Trash the cwd copy */
    if (tsdPtr->cwdPathPtr != NULL) {
	Tcl_DecrRefCount(tsdPtr->cwdPathPtr);
    }



    /* Trash the filesystems cache */
    fsRecPtr = tsdPtr->filesystemList;
    while (fsRecPtr != NULL) {
	tmpFsRecPtr = fsRecPtr->nextPtr;
	if (--fsRecPtr->fileRefCount <= 0) {
	    ckfree((char *)fsRecPtr);
	}
	fsRecPtr = tmpFsRecPtr;
    }
}






















int 
TclFSCwdPointerEquals(objPtr)
    Tcl_Obj* objPtr;
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);

    Tcl_MutexLock(&cwdMutex);
    if (tsdPtr->cwdPathPtr == NULL
	    || tsdPtr->cwdPathEpoch != cwdPathEpoch) {
	if (tsdPtr->cwdPathPtr) {
	    Tcl_DecrRefCount(tsdPtr->cwdPathPtr);
	}



        if (cwdPathPtr == NULL) {
    	    tsdPtr->cwdPathPtr = NULL;
        } else {
    	    tsdPtr->cwdPathPtr = Tcl_DuplicateObj(cwdPathPtr);
    	    Tcl_IncrRefCount(tsdPtr->cwdPathPtr);
        }





	tsdPtr->cwdPathEpoch = cwdPathEpoch;
    }
    Tcl_MutexUnlock(&cwdMutex);

    if (tsdPtr->initialized == 0) {
	Tcl_CreateThreadExitHandler(FsThrExitProc, (ClientData)tsdPtr);
	tsdPtr->initialized = 1;
    }


    return (tsdPtr->cwdPathPtr == objPtr); 






















}

#ifdef TCL_THREADS
static void
FsRecacheFilesystemList(void)
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);







>
>
>











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

|
|






|


>
>
>






>
>
>
>
>









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







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
    ThreadSpecificData *tsdPtr = (ThreadSpecificData*)cd;
    FilesystemRecord *fsRecPtr = NULL, *tmpFsRecPtr = NULL;

    /* Trash the cwd copy */
    if (tsdPtr->cwdPathPtr != NULL) {
	Tcl_DecrRefCount(tsdPtr->cwdPathPtr);
    }
    if (tsdPtr->cwdClientData != NULL) {
	NativeFreeInternalRep(tsdPtr->cwdClientData);
    }
    /* Trash the filesystems cache */
    fsRecPtr = tsdPtr->filesystemList;
    while (fsRecPtr != NULL) {
	tmpFsRecPtr = fsRecPtr->nextPtr;
	if (--fsRecPtr->fileRefCount <= 0) {
	    ckfree((char *)fsRecPtr);
	}
	fsRecPtr = tmpFsRecPtr;
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TclFSCwdPointerEquals --
 *
 *	Check whether the current working directory is equal to the
 *	path given.  
 *	
 * Results:
 *	1 (equal) or 0 (un-equal) as appropriate.
 *
 * Side effects:
 *	If the paths are equal, but are not the same object, this
 *	method will modify the given pathPtrPtr to refer to the same
 *	object.  In this case the object pointed to by pathPtrPtr will
 *	have its refCount decremented, and it will be adjusted to 
 *	point to the cwd (with a new refCount).
 *
 *----------------------------------------------------------------------
 */

int 
TclFSCwdPointerEquals(pathPtrPtr)
    Tcl_Obj** pathPtrPtr;
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);

    Tcl_MutexLock(&cwdMutex);
    if (tsdPtr->cwdPathPtr == NULL
	    || tsdPtr->cwdPathEpoch != cwdPathEpoch) {
	if (tsdPtr->cwdPathPtr != NULL) {
	    Tcl_DecrRefCount(tsdPtr->cwdPathPtr);
	}
	if (tsdPtr->cwdClientData != NULL) {
	    NativeFreeInternalRep(tsdPtr->cwdClientData);
	}
        if (cwdPathPtr == NULL) {
    	    tsdPtr->cwdPathPtr = NULL;
        } else {
    	    tsdPtr->cwdPathPtr = Tcl_DuplicateObj(cwdPathPtr);
    	    Tcl_IncrRefCount(tsdPtr->cwdPathPtr);
        }
	if (cwdClientData == NULL) {
	    tsdPtr->cwdClientData = NULL;
	} else {
	    tsdPtr->cwdClientData = TclNativeDupInternalRep(cwdClientData);
	}
	tsdPtr->cwdPathEpoch = cwdPathEpoch;
    }
    Tcl_MutexUnlock(&cwdMutex);

    if (tsdPtr->initialized == 0) {
	Tcl_CreateThreadExitHandler(FsThrExitProc, (ClientData)tsdPtr);
	tsdPtr->initialized = 1;
    }

    if (pathPtrPtr == NULL) {
        return (tsdPtr->cwdPathPtr == NULL);
    }
    
    if (tsdPtr->cwdPathPtr == *pathPtrPtr) {
        return 1;
    } else {
	int len1, len2;
	CONST char *str1, *str2;
	str1 = Tcl_GetStringFromObj(tsdPtr->cwdPathPtr, &len1);
	str2 = Tcl_GetStringFromObj(*pathPtrPtr, &len2);
	if (len1 == len2 && !strcmp(str1,str2)) {
	    /* 
	     * They are equal, but different objects.  Update so they
	     * will be the same object in the future.
	     */
	    Tcl_DecrRefCount(*pathPtrPtr);
	    *pathPtrPtr = tsdPtr->cwdPathPtr;
	    Tcl_IncrRefCount(*pathPtrPtr);
	    return 1;
	} else {
	    return 0;
	}
    }
}

#ifdef TCL_THREADS
static void
FsRecacheFilesystemList(void)
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
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
    }
    Tcl_MutexUnlock(&filesystemMutex);
    fsRecPtr = tsdPtr->filesystemList;
#endif
    return fsRecPtr;
}




static void
FsUpdateCwd(cwdObj)
    Tcl_Obj *cwdObj;

{
    int len;
    char *str = NULL;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);

    if (cwdObj != NULL) {
	str = Tcl_GetStringFromObj(cwdObj, &len);
    }

    Tcl_MutexLock(&cwdMutex);
    if (cwdPathPtr != NULL) {
        Tcl_DecrRefCount(cwdPathPtr);
    }



    if (cwdObj == NULL) {
	cwdPathPtr = NULL;

    } else {
	/* This must be stored as string obj! */
	cwdPathPtr = Tcl_NewStringObj(str, len); 
    	Tcl_IncrRefCount(cwdPathPtr);

    }
    cwdPathEpoch++;
    tsdPtr->cwdPathEpoch = cwdPathEpoch;
    Tcl_MutexUnlock(&cwdMutex);

    if (tsdPtr->cwdPathPtr) {
        Tcl_DecrRefCount(tsdPtr->cwdPathPtr);
    }



    if (cwdObj == NULL) {
	tsdPtr->cwdPathPtr = NULL;

    } else {
	tsdPtr->cwdPathPtr = Tcl_NewStringObj(str, len); 

	Tcl_IncrRefCount(tsdPtr->cwdPathPtr);
    }
}

/*
 *----------------------------------------------------------------------
 *







>
>
>

|

>













>
>
>


>




>








>
>
>


>


>







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
    }
    Tcl_MutexUnlock(&filesystemMutex);
    fsRecPtr = tsdPtr->filesystemList;
#endif
    return fsRecPtr;
}

/* 
 * If non-NULL, clientData is owned by us and must be freed later.
 */
static void
FsUpdateCwd(cwdObj, clientData)
    Tcl_Obj *cwdObj;
    ClientData clientData;
{
    int len;
    char *str = NULL;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);

    if (cwdObj != NULL) {
	str = Tcl_GetStringFromObj(cwdObj, &len);
    }

    Tcl_MutexLock(&cwdMutex);
    if (cwdPathPtr != NULL) {
        Tcl_DecrRefCount(cwdPathPtr);
    }
    if (cwdClientData != NULL) {
	NativeFreeInternalRep(cwdClientData);
    }
    if (cwdObj == NULL) {
	cwdPathPtr = NULL;
	cwdClientData = NULL;
    } else {
	/* This must be stored as string obj! */
	cwdPathPtr = Tcl_NewStringObj(str, len); 
    	Tcl_IncrRefCount(cwdPathPtr);
	cwdClientData = TclNativeDupInternalRep(clientData);
    }
    cwdPathEpoch++;
    tsdPtr->cwdPathEpoch = cwdPathEpoch;
    Tcl_MutexUnlock(&cwdMutex);

    if (tsdPtr->cwdPathPtr) {
        Tcl_DecrRefCount(tsdPtr->cwdPathPtr);
    }
    if (tsdPtr->cwdClientData) {
	NativeFreeInternalRep(tsdPtr->cwdClientData);
    }
    if (cwdObj == NULL) {
	tsdPtr->cwdPathPtr = NULL;
	tsdPtr->cwdClientData = NULL;
    } else {
	tsdPtr->cwdPathPtr = Tcl_NewStringObj(str, len); 
	tsdPtr->cwdClientData = clientData;
	Tcl_IncrRefCount(tsdPtr->cwdPathPtr);
    }
}

/*
 *----------------------------------------------------------------------
 *
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
 *
 *----------------------------------------------------------------------
 */

void
TclFinalizeFilesystem()
{
    FilesystemRecord *fsRecPtr, *tmpFsRecPtr;

    /* 
     * Assumption that only one thread is active now.  Otherwise
     * we would need to put various mutexes around this code.
     */
    
    if (cwdPathPtr != NULL) {
	Tcl_DecrRefCount(cwdPathPtr);
	cwdPathPtr = NULL;
        cwdPathEpoch = 0;
    }





    /* 
     * Remove all filesystems, freeing any allocated memory
     * that is no longer needed
     */

    fsRecPtr = filesystemList;
    while (fsRecPtr != NULL) {
        tmpFsRecPtr = filesystemList->nextPtr;
        if (fsRecPtr->fileRefCount <= 0) {
            /* The native filesystem is static, so we don't free it */
            if (fsRecPtr != &nativeFilesystemRecord) {
                ckfree((char *)fsRecPtr);
            }
        }
        fsRecPtr = tmpFsRecPtr;







|











>
>
>
>








|







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
 *
 *----------------------------------------------------------------------
 */

void
TclFinalizeFilesystem()
{
    FilesystemRecord *fsRecPtr;

    /* 
     * Assumption that only one thread is active now.  Otherwise
     * we would need to put various mutexes around this code.
     */
    
    if (cwdPathPtr != NULL) {
	Tcl_DecrRefCount(cwdPathPtr);
	cwdPathPtr = NULL;
        cwdPathEpoch = 0;
    }
    if (cwdClientData != NULL) {
	NativeFreeInternalRep(cwdClientData);
	cwdClientData = NULL;
    }

    /* 
     * Remove all filesystems, freeing any allocated memory
     * that is no longer needed
     */

    fsRecPtr = filesystemList;
    while (fsRecPtr != NULL) {
	FilesystemRecord *tmpFsRecPtr = fsRecPtr->nextPtr;
        if (fsRecPtr->fileRefCount <= 0) {
            /* The native filesystem is static, so we don't free it */
            if (fsRecPtr != &nativeFilesystemRecord) {
                ckfree((char *)fsRecPtr);
            }
        }
        fsRecPtr = tmpFsRecPtr;
918
919
920
921
922
923
924













925




926
927
928
929
930
931
932
    Tcl_Obj *result;		/* List object to receive results. */
    Tcl_Obj *pathPtr;	        /* Contains path to directory to search. */
    CONST char *pattern;	/* Pattern to match against. */
    Tcl_GlobTypeData *types;	/* Object containing list of acceptable types.
				 * May be NULL. In particular the directory
				 * flag is very important. */
{













    Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr);




    if (fsPtr != NULL) {
	Tcl_FSMatchInDirectoryProc *proc = fsPtr->matchInDirectoryProc;
	if (proc != NULL) {
	    int ret = (*proc)(interp, result, pathPtr, pattern, types);
	    if (ret == TCL_OK && pattern != NULL) {
		result = FsAddMountsToGlobResult(result, pathPtr, 
						 pattern, types);







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







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
    Tcl_Obj *result;		/* List object to receive results. */
    Tcl_Obj *pathPtr;	        /* Contains path to directory to search. */
    CONST char *pattern;	/* Pattern to match against. */
    Tcl_GlobTypeData *types;	/* Object containing list of acceptable types.
				 * May be NULL. In particular the directory
				 * flag is very important. */
{
    Tcl_Filesystem *fsPtr;
    
    if (types != NULL && types->type & TCL_GLOB_TYPE_MOUNT) {
	/* 
	 * We don't currently allow querying of mounts by external code
	 * (a valuable future step), so since we're the only function
	 * that actually knows about mounts, this means we're being
	 * called recursively by ourself.  Return no matches.
	 */
	return TCL_OK;
    }
    
    if (pathPtr != NULL) {
        fsPtr = Tcl_FSGetFileSystemForPath(pathPtr);
    } else {
	fsPtr = NULL;
    }
    
    if (fsPtr != NULL) {
	Tcl_FSMatchInDirectoryProc *proc = fsPtr->matchInDirectoryProc;
	if (proc != NULL) {
	    int ret = (*proc)(interp, result, pathPtr, pattern, types);
	    if (ret == TCL_OK && pattern != NULL) {
		result = FsAddMountsToGlobResult(result, pathPtr, 
						 pattern, types);
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030


1031
1032
1033
1034
1035
1036
1037
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------- 
 */
static Tcl_Obj*
FsAddMountsToGlobResult(result, pathPtr, pattern, types)
    Tcl_Obj *result;    /* The current list of matching paths */
    Tcl_Obj *pathPtr;   /* The directory in question */
    CONST char *pattern;
    Tcl_GlobTypeData *types;


{
    int mLength, gLength, i;
    int dir = (types == NULL || (types->type & TCL_GLOB_TYPE_DIR));
    Tcl_Obj *mounts = FsListMounts(pathPtr, pattern);

    if (mounts == NULL) return result; 








|
|
|
|
>
>







1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------- 
 */
static Tcl_Obj*
FsAddMountsToGlobResult(result, pathPtr, pattern, types)
    Tcl_Obj *result;            /* The current list of matching paths */
    Tcl_Obj *pathPtr;           /* The directory in question */
    CONST char *pattern;        /* Pattern to match against. */
    Tcl_GlobTypeData *types;	/* Object containing list of acceptable types.
				 * May be NULL. In particular the directory
				 * flag is very important. */
{
    int mLength, gLength, i;
    int dir = (types == NULL || (types->type & TCL_GLOB_TYPE_DIR));
    Tcl_Obj *mounts = FsListMounts(pathPtr, pattern);

    if (mounts == NULL) return result; 

1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240



1241
1242
1243
1244
1245
1246
1247
 *      to a directory separator that we know exists and is already
 *      normalized (so it is important not to point to the char just
 *      after the separator).
 *---------------------------------------------------------------------------
 */
int
TclFSNormalizeToUniquePath(interp, pathPtr, startAt, clientDataPtr)
    Tcl_Interp *interp;
    Tcl_Obj *pathPtr;
    int startAt;
    ClientData *clientDataPtr;



{
    FilesystemRecord *fsRecPtr, *firstFsRecPtr;
    /* Ignore this variable */
    (void)clientDataPtr;
    
    /*
     * Call each of the "normalise path" functions in succession. This is







|
|
|
|
>
>
>







1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
 *      to a directory separator that we know exists and is already
 *      normalized (so it is important not to point to the char just
 *      after the separator).
 *---------------------------------------------------------------------------
 */
int
TclFSNormalizeToUniquePath(interp, pathPtr, startAt, clientDataPtr)
    Tcl_Interp *interp;         /* Used for error messages. */
    Tcl_Obj *pathPtr;           /* The path to normalize in place */
    int startAt;                /* Start at this char-offset */
    ClientData *clientDataPtr;  /* If we generated a complete
                                 * normalized path for a given
                                 * filesystem, we can optionally return
                                 * an fs-specific clientdata here. */ 
{
    FilesystemRecord *fsRecPtr, *firstFsRecPtr;
    /* Ignore this variable */
    (void)clientDataPtr;
    
    /*
     * Call each of the "normalise path" functions in succession. This is
1493
1494
1495
1496
1497
1498
1499
1500

1501
1502
1503
1504
1505
1506
1507
 */

int
Tcl_FSEvalFileEx(interp, pathPtr, encodingName)
    Tcl_Interp *interp;		/* Interpreter in which to process file. */
    Tcl_Obj *pathPtr;		/* Path of file to process.  Tilde-substitution
				 * will be performed on this name. */
    CONST char *encodingName;

{
    int result;
    Tcl_StatBuf statBuf;
    Tcl_Obj *oldScriptFile;
    Interp *iPtr;
    Tcl_Channel chan;
    Tcl_Obj *objPtr;







|
>







1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
 */

int
Tcl_FSEvalFileEx(interp, pathPtr, encodingName)
    Tcl_Interp *interp;		/* Interpreter in which to process file. */
    Tcl_Obj *pathPtr;		/* Path of file to process.  Tilde-substitution
				 * will be performed on this name. */
    CONST char *encodingName;   /* If non-NULL, then use this encoding 
                                 * for the file. */
{
    int result;
    Tcl_StatBuf statBuf;
    Tcl_Obj *oldScriptFile;
    Interp *iPtr;
    Tcl_Channel chan;
    Tcl_Obj *objPtr;
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550

    Tcl_SetChannelOption(interp, chan, "-eofchar", "\32");
    /*
     * If the encoding is specified, set it for the channel.
     * Else don't touch it (and use the system encoding)
     * Report error on unknown encoding.
     */
    if (encodingName) {
	if (Tcl_SetChannelOption(interp, chan, "-encoding", encodingName)
		!= TCL_OK) {
	    Tcl_Close(interp,chan);
	    goto end;
	}
    }
    if (Tcl_ReadChars(chan, objPtr, -1, 0) < 0) {







|







1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649

    Tcl_SetChannelOption(interp, chan, "-eofchar", "\32");
    /*
     * If the encoding is specified, set it for the channel.
     * Else don't touch it (and use the system encoding)
     * Report error on unknown encoding.
     */
    if (encodingName != NULL) {
	if (Tcl_SetChannelOption(interp, chan, "-encoding", encodingName)
		!= TCL_OK) {
	    Tcl_Close(interp,chan);
	    goto end;
	}
    }
    if (Tcl_ReadChars(chan, objPtr, -1, 0) < 0) {
2304
2305
2306
2307
2308
2309
2310








































2311

2312
2313
2314
2315
2316
2317
2318
	 * succeeded.
	 */

	fsRecPtr = FsGetFirstFilesystem();
	while ((retVal == NULL) && (fsRecPtr != NULL)) {
	    Tcl_FSGetCwdProc *proc = fsRecPtr->fsPtr->getCwdProc;
	    if (proc != NULL) {








































		retVal = (*proc)(interp);

	    }
	    fsRecPtr = fsRecPtr->nextPtr;
	}
	/* 
	 * Now the 'cwd' may NOT be normalized, at least on some
	 * platforms.  For the sake of efficiency, we want a completely
	 * normalized cwd at all times.







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







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
	 * succeeded.
	 */

	fsRecPtr = FsGetFirstFilesystem();
	while ((retVal == NULL) && (fsRecPtr != NULL)) {
	    Tcl_FSGetCwdProc *proc = fsRecPtr->fsPtr->getCwdProc;
	    if (proc != NULL) {
		if (fsRecPtr->fsPtr->version != TCL_FILESYSTEM_VERSION_1) {
		    ClientData retCd;
		    TclFSGetCwdProc2 *proc2 = (TclFSGetCwdProc2*)proc;
		    
		    retCd = (*proc2)(NULL);
		    if (retCd != NULL) {
			Tcl_Obj *norm;
			/* Looks like a new current directory */
			retVal = (*fsRecPtr->fsPtr->internalToNormalizedProc)(retCd);
			Tcl_IncrRefCount(retVal);
			norm = TclFSNormalizeAbsolutePath(interp, retVal, NULL);
			if (norm != NULL) {
			    /* 
			     * We found a cwd, which is now in our global storage.
			     * We must make a copy. Norm already has a refCount of 1.
			     * 
			     * Threading issue: note that multiple threads at system
			     * startup could in principle call this procedure 
			     * simultaneously.  They will therefore each set the
			     * cwdPathPtr independently.  That behaviour is a bit
			     * peculiar, but should be fine.  Once we have a cwd,
			     * we'll always be in the 'else' branch below which
			     * is simpler.
			     */
			    FsUpdateCwd(norm, retCd);
			    Tcl_DecrRefCount(norm);
			} else {
			    (*fsRecPtr->fsPtr->freeInternalRepProc)(retCd);
			}
			Tcl_DecrRefCount(retVal);
			retVal = NULL;
			goto cdDidNotChange;
		    } else {
			if (interp != NULL) {
			    Tcl_AppendResult(interp,
				    "error getting working directory name: ",
				    Tcl_PosixError(interp), (char *) NULL);
			}
		    }
		} else {
		    retVal = (*proc)(interp);
		}
	    }
	    fsRecPtr = fsRecPtr->nextPtr;
	}
	/* 
	 * Now the 'cwd' may NOT be normalized, at least on some
	 * platforms.  For the sake of efficiency, we want a completely
	 * normalized cwd at all times.
2331
2332
2333
2334
2335
2336
2337

2338

2339
2340
2341
2342
2343
2344
2345
		 * startup could in principle call this procedure 
		 * simultaneously.  They will therefore each set the
		 * cwdPathPtr independently.  That behaviour is a bit
		 * peculiar, but should be fine.  Once we have a cwd,
		 * we'll always be in the 'else' branch below which
		 * is simpler.
		 */

                FsUpdateCwd(norm);

	    }
	    Tcl_DecrRefCount(retVal);
	}
    } else {
	/* 
	 * We already have a cwd cached, but we want to give the
	 * filesystem it is in a chance to check whether that cwd







>
|
>







2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
		 * startup could in principle call this procedure 
		 * simultaneously.  They will therefore each set the
		 * cwdPathPtr independently.  That behaviour is a bit
		 * peculiar, but should be fine.  Once we have a cwd,
		 * we'll always be in the 'else' branch below which
		 * is simpler.
		 */
		ClientData cd = (ClientData) Tcl_FSGetNativePath(norm);
		FsUpdateCwd(norm, TclNativeDupInternalRep(cd));
		Tcl_DecrRefCount(norm);
	    }
	    Tcl_DecrRefCount(retVal);
	}
    } else {
	/* 
	 * We already have a cwd cached, but we want to give the
	 * filesystem it is in a chance to check whether that cwd
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
	 * (if the cwd returns NULL).  This ensures that, say, on Unix
	 * if the permissions of the cwd change, 'pwd' does actually
	 * throw the correct error in Tcl.  (This is tested for in the
	 * test suite on unix).
	 */
	if (fsPtr != NULL) {
	    Tcl_FSGetCwdProc *proc = fsPtr->getCwdProc;

	    if (proc != NULL) {
		Tcl_Obj *retVal = (*proc)(interp);




















		if (retVal != NULL) {
		    Tcl_Obj *norm = TclFSNormalizeAbsolutePath(interp, retVal, NULL);

		    /* 
		     * Check whether cwd has changed from the value
		     * previously stored in cwdPathPtr.  Really 'norm'
		     * shouldn't be null, but we are careful.
		     */
		    if (norm == NULL) {
			/* Do nothing */



		    } else if (Tcl_FSEqualPaths(tsdPtr->cwdPathPtr, norm)) {
			/* 
			 * If the paths were equal, we can be more
			 * efficient and retain the old path object
			 * which will probably already be shared.  In
			 * this case we can simply free the normalized
			 * path we just calculated.
			 */
			Tcl_DecrRefCount(norm);



		    } else {
			FsUpdateCwd(norm);

		    }
		    Tcl_DecrRefCount(retVal);
		} else {
		    /* The 'cwd' function returned an error; reset the cwd */
		    FsUpdateCwd(NULL);
		}
	    }
	}
    }
    

    if (tsdPtr->cwdPathPtr != NULL) {
	Tcl_IncrRefCount(tsdPtr->cwdPathPtr);
    }
    
    return tsdPtr->cwdPathPtr; 
}








>

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

|
>







>
>
>









>
>
>

|
>




|





>







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
	 * (if the cwd returns NULL).  This ensures that, say, on Unix
	 * if the permissions of the cwd change, 'pwd' does actually
	 * throw the correct error in Tcl.  (This is tested for in the
	 * test suite on unix).
	 */
	if (fsPtr != NULL) {
	    Tcl_FSGetCwdProc *proc = fsPtr->getCwdProc;
	    ClientData retCd = NULL;
	    if (proc != NULL) {
		Tcl_Obj *retVal;
		if (fsPtr->version != TCL_FILESYSTEM_VERSION_1) {
		    TclFSGetCwdProc2 *proc2 = (TclFSGetCwdProc2*)proc;
		    
		    retCd = (*proc2)(tsdPtr->cwdClientData);
		    if (retCd == NULL && interp != NULL) {
			Tcl_AppendResult(interp,
				"error getting working directory name: ",
				Tcl_PosixError(interp), (char *) NULL);
		    }
		    
		    if (retCd == tsdPtr->cwdClientData) {
			goto cdDidNotChange;
		    }
		    
		    /* Looks like a new current directory */
		    retVal = (*fsPtr->internalToNormalizedProc)(retCd);
		    Tcl_IncrRefCount(retVal);
		} else {
		    retVal = (*proc)(interp);
		}
		if (retVal != NULL) {
		    Tcl_Obj *norm = TclFSNormalizeAbsolutePath(interp, retVal, 
							       NULL);
		    /* 
		     * Check whether cwd has changed from the value
		     * previously stored in cwdPathPtr.  Really 'norm'
		     * shouldn't be null, but we are careful.
		     */
		    if (norm == NULL) {
			/* Do nothing */
			if (retCd != NULL) {
			    (*fsPtr->freeInternalRepProc)(retCd);
			}
		    } else if (Tcl_FSEqualPaths(tsdPtr->cwdPathPtr, norm)) {
			/* 
			 * If the paths were equal, we can be more
			 * efficient and retain the old path object
			 * which will probably already be shared.  In
			 * this case we can simply free the normalized
			 * path we just calculated.
			 */
			Tcl_DecrRefCount(norm);
			if (retCd != NULL) {
			    (*fsPtr->freeInternalRepProc)(retCd);
			}
		    } else {
			FsUpdateCwd(norm, retCd);
			Tcl_DecrRefCount(norm);
		    }
		    Tcl_DecrRefCount(retVal);
		} else {
		    /* The 'cwd' function returned an error; reset the cwd */
		    FsUpdateCwd(NULL, NULL);
		}
	    }
	}
    }
    
  cdDidNotChange:
    if (tsdPtr->cwdPathPtr != NULL) {
	Tcl_IncrRefCount(tsdPtr->cwdPathPtr);
    }
    
    return tsdPtr->cwdPathPtr; 
}

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
	     * will have been cached as a result of the
	     * Tcl_FSGetFileSystemForPath call above anyway).
	     */
	    Tcl_Obj *normDirName = Tcl_FSGetNormalizedPath(NULL, pathPtr);
	    if (normDirName == NULL) {
	        return TCL_ERROR;
	    }




























	    FsUpdateCwd(normDirName);

	}
    } else {
	Tcl_SetErrno(ENOENT);
    }
    
    return (retVal);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_FSLoadFile --
 *
 *	Dynamically loads a binary code file into memory and returns
 *	the addresses of two procedures within that file, if they are
 *	defined.  The appropriate function for the filesystem to which
 *	pathPtr belongs will be called.
 *	
 *	Note that the native filesystem doesn't actually assume
 *	'pathPtr' is a path.  Rather it assumes filename is either
 *	a path or just the name of a file which can be found somewhere
 *	in the environment's loadable path.  This behaviour is not
 *	very compatible with virtual filesystems (and has other problems
 *	documented in the load man-page), so it is advised that full
 *	paths are always used.
 *
 * Results:
 *	A standard Tcl completion code.  If an error occurs, an error
 *	message is left in the interp's result.
 *







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


















|
|
|
|
|







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
	     * will have been cached as a result of the
	     * Tcl_FSGetFileSystemForPath call above anyway).
	     */
	    Tcl_Obj *normDirName = Tcl_FSGetNormalizedPath(NULL, pathPtr);
	    if (normDirName == NULL) {
	        return TCL_ERROR;
	    }
	    if (fsPtr == &tclNativeFilesystem) {
		/* 
		 * For the native filesystem, we keep a cache of the
		 * native representation of the cwd.  But, we want to do
		 * that for the exact format that is returned by
		 * 'getcwd' (so that we can later compare the two
		 * representations for equality), which might not be
		 * exactly the same char-string as the native
		 * representation of the fully normalized path (e.g. on
		 * Windows there's a forward-slash vs backslash
		 * difference).  Hence we ask for this again here.  On
		 * Unix it might actually be true that we always have
		 * the correct form in the native rep in which case we
		 * could simply use:
		 * 
		 * cd = Tcl_FSGetNativePath(pathPtr);
		 * 
		 * instead.  This should be examined by someone on
		 * Unix.
		 */
		ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
		ClientData cd;

		/* Assumption we are using a filesystem version 2 */
		TclFSGetCwdProc2 *proc2 = (TclFSGetCwdProc2*)fsPtr->getCwdProc;
		cd = (*proc2)(tsdPtr->cwdClientData);
		FsUpdateCwd(normDirName, TclNativeDupInternalRep(cd));
	    } else {
		FsUpdateCwd(normDirName, NULL);
	    }
	}
    } else {
	Tcl_SetErrno(ENOENT);
    }
    
    return (retVal);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_FSLoadFile --
 *
 *	Dynamically loads a binary code file into memory and returns
 *	the addresses of two procedures within that file, if they are
 *	defined.  The appropriate function for the filesystem to which
 *	pathPtr belongs will be called.
 *	
 *	Note that the native filesystem doesn't actually assume 'pathPtr'
 *	is a path.  Rather it assumes pathPtr is either a path or just
 *	the name (tail) of a file which can be found somewhere in the
 *	environment's loadable path.  This behaviour is not very
 *	compatible with virtual filesystems (and has other problems
 *	documented in the load man-page), so it is advised that full
 *	paths are always used.
 *
 * Results:
 *	A standard Tcl completion code.  If an error occurs, an error
 *	message is left in the interp's result.
 *
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
    CONST char *sym1, *sym2;	/* Names of two procedures to look up in
				 * the file's symbol table. */
    Tcl_PackageInitProc **proc1Ptr, **proc2Ptr;
				/* Where to return the addresses corresponding
				 * to sym1 and sym2. */
    Tcl_LoadHandle *handlePtr;	/* Filled with token for dynamically loaded
				 * file which will be passed back to 
				 * (*unloadProcPtr)() to unload the file. */
    Tcl_FSUnloadFileProc **unloadProcPtr;	
                                /* Filled with address of Tcl_FSUnloadFileProc
                                 * function which should be used for
                                 * this file. */
{

























































































    Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr);
    if (fsPtr != NULL) {
	Tcl_FSLoadFileProc *proc = fsPtr->loadFileProc;
	if (proc != NULL) {

	    int retVal = (*proc)(interp, pathPtr, handlePtr, unloadProcPtr);
	    if (retVal != TCL_OK) {
		return retVal;
	    }
	    if (*handlePtr == NULL) {
		return TCL_ERROR;
	    }

	    if (sym1 != NULL) {
	        *proc1Ptr = TclpFindSymbol(interp, *handlePtr, sym1);

	    }
	    if (sym2 != NULL) {
	        *proc2Ptr = TclpFindSymbol(interp, *handlePtr, sym2);
	    }


	    return retVal;
	} else {
	    Tcl_Filesystem *copyFsPtr;
	    Tcl_Obj *copyToPtr;
	    
	    /* First check if it is readable -- and exists! */
	    if (Tcl_FSAccess(pathPtr, R_OK) != 0) {









|
|
|

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




>







>
|
|
>
|
<
<

>
>







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
    CONST char *sym1, *sym2;	/* Names of two procedures to look up in
				 * the file's symbol table. */
    Tcl_PackageInitProc **proc1Ptr, **proc2Ptr;
				/* Where to return the addresses corresponding
				 * to sym1 and sym2. */
    Tcl_LoadHandle *handlePtr;	/* Filled with token for dynamically loaded
				 * file which will be passed back to 
				 * (*unloadProcPtr)() to unload the file. */
    Tcl_FSUnloadFileProc **unloadProcPtr;	
				/* Filled with address of Tcl_FSUnloadFileProc
				 * function which should be used for
				 * this file. */
{
    CONST char *symbols[2];
    Tcl_PackageInitProc **procPtrs[2];
    ClientData clientData;
    int res;
    
    /* Initialize the arrays */
    symbols[0] = sym1;
    symbols[1] = sym2;
    procPtrs[0] = proc1Ptr;
    procPtrs[1] = proc2Ptr;
    
    /* Perform the load */
    res = TclLoadFile(interp, pathPtr, 2, symbols, procPtrs, 
		      handlePtr, &clientData, unloadProcPtr);
    
    /* 
     * Due to an unfortunate mis-design in Tcl 8.4 fs, when loading a
     * shared library, we don't keep the loadHandle (for TclpFindSymbol)
     * and the clientData (for the unloadProc) separately.  In fact we
     * effectively throw away the loadHandle and only use the clientData.
     * It just so happens, for the native filesystem only, that these two
     * are identical.
     * 
     * This also means that the signatures Tcl_FSUnloadFileProc and
     * Tcl_FSLoadFileProc are both misleading.
     */
    *handlePtr = (Tcl_LoadHandle) clientData;
    return res;
}

/*
 *----------------------------------------------------------------------
 *
 * TclLoadFile --
 *
 *	Dynamically loads a binary code file into memory and returns the
 *	addresses of a number of given procedures within that file, if
 *	they are defined.  The appropriate function for the filesystem to
 *	which pathPtr belongs will be called.
 *	
 *	Note that the native filesystem doesn't actually assume 'pathPtr'
 *	is a path.  Rather it assumes pathPtr is either a path or just
 *	the name (tail) of a file which can be found somewhere in the
 *	environment's loadable path.  This behaviour is not very
 *	compatible with virtual filesystems (and has other problems
 *	documented in the load man-page), so it is advised that full
 *	paths are always used.
 *	
 *	This function is currently private to Tcl.  It may be exported in
 *	the future and its interface fixed (but we should clean up the
 *	loadHandle/clientData confusion at that time -- see the above
 *	comments in Tcl_FSLoadFile for details).  For a public function,
 *	see Tcl_FSLoadFile.
 *
 * Results:
 *	A standard Tcl completion code.  If an error occurs, an error
 *	message is left in the interp's result.
 *
 * Side effects:
 *	New code suddenly appears in memory.  This may later be
 *	unloaded by passing the clientData to the unloadProc.
 *
 *----------------------------------------------------------------------
 */

int
TclLoadFile(interp, pathPtr, symc, symbols, procPtrs, 
	    handlePtr, clientDataPtr, unloadProcPtr)
    Tcl_Interp *interp;		/* Used for error reporting. */
    Tcl_Obj *pathPtr;		/* Name of the file containing the desired
				 * code. */
    int symc;                   /* Number of symbols/procPtrs in the
                                 * next two arrays. */
    CONST char *symbols[];	/* Names of procedures to look up in
				 * the file's symbol table. */
    Tcl_PackageInitProc **procPtrs[];
				/* Where to return the addresses
				 * corresponding to symbols[].  */
    Tcl_LoadHandle *handlePtr;	/* Filled with token for shared
                              	 * library information which can be
                              	 * used in TclpFindSymbol. */
    ClientData *clientDataPtr;	/* Filled with token for dynamically loaded
				 * file which will be passed back to 
				 * (*unloadProcPtr)() to unload the file. */
    Tcl_FSUnloadFileProc **unloadProcPtr;	
                                /* Filled with address of Tcl_FSUnloadFileProc
                                 * function which should be used for
                                 * this file. */
{
    Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr);
    if (fsPtr != NULL) {
	Tcl_FSLoadFileProc *proc = fsPtr->loadFileProc;
	if (proc != NULL) {
	    int i;
	    int retVal = (*proc)(interp, pathPtr, handlePtr, unloadProcPtr);
	    if (retVal != TCL_OK) {
		return retVal;
	    }
	    if (*handlePtr == NULL) {
		return TCL_ERROR;
	    }
	    for (i = 0;i < symc;i++) {
	        if (symbols[i] != NULL) {
	            *procPtrs[i] = TclpFindSymbol(interp, *handlePtr, 
						  symbols[i]);
	        }


	    }
	    /* Copy this across, since both are equal for the native fs */
	    *clientDataPtr = (ClientData)*handlePtr;
	    return retVal;
	} else {
	    Tcl_Filesystem *copyFsPtr;
	    Tcl_Obj *copyToPtr;
	    
	    /* First check if it is readable -- and exists! */
	    if (Tcl_FSAccess(pathPtr, R_OK) != 0) {
2581
2582
2583
2584
2585
2586
2587

2588
2589
2590
2591
2592
2593
2594
		Tcl_DecrRefCount(copyToPtr);
		return -1;
	    }
	    
	    if (TclCrossFilesystemCopy(interp, pathPtr, 
				       copyToPtr) == TCL_OK) {
		Tcl_LoadHandle newLoadHandle = NULL;

		Tcl_FSUnloadFileProc *newUnloadProcPtr = NULL;
		FsDivertLoad *tvdlPtr;
		int retVal;

#if !defined(__WIN32__) && !defined(MAC_TCL)
		/* 
		 * Do we need to set appropriate permissions 







>







2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
		Tcl_DecrRefCount(copyToPtr);
		return -1;
	    }
	    
	    if (TclCrossFilesystemCopy(interp, pathPtr, 
				       copyToPtr) == TCL_OK) {
		Tcl_LoadHandle newLoadHandle = NULL;
		ClientData newClientData = NULL;
		Tcl_FSUnloadFileProc *newUnloadProcPtr = NULL;
		FsDivertLoad *tvdlPtr;
		int retVal;

#if !defined(__WIN32__) && !defined(MAC_TCL)
		/* 
		 * Do we need to set appropriate permissions 
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617

2618
2619
2620
2621
2622
2623
2624
2625
		/* 
		 * We need to reset the result now, because the cross-
		 * filesystem copy may have stored the number of bytes
		 * in the result
		 */
		Tcl_ResetResult(interp);
		
		retVal = Tcl_FSLoadFile(interp, copyToPtr, sym1, sym2,
					proc1Ptr, proc2Ptr, 
					&newLoadHandle,

					&newUnloadProcPtr);
	        if (retVal != TCL_OK) {
		    /* The file didn't load successfully */
		    Tcl_FSDeleteFile(copyToPtr);
		    Tcl_DecrRefCount(copyToPtr);
		    return retVal;
		}
		/* 







|
<
|
>
|







2902
2903
2904
2905
2906
2907
2908
2909

2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
		/* 
		 * We need to reset the result now, because the cross-
		 * filesystem copy may have stored the number of bytes
		 * in the result
		 */
		Tcl_ResetResult(interp);
		
		retVal = TclLoadFile(interp, copyToPtr, symc, symbols, 

				     procPtrs, &newLoadHandle, 
				     &newClientData,
				     &newUnloadProcPtr);
	        if (retVal != TCL_OK) {
		    /* The file didn't load successfully */
		    Tcl_FSDeleteFile(copyToPtr);
		    Tcl_DecrRefCount(copyToPtr);
		    return retVal;
		}
		/* 
2634
2635
2636
2637
2638
2639
2640

2641
2642
2643
2644
2645
2646
2647
		     * library which was loaded.  Note that this
		     * does mean that the package list maintained
		     * by 'load' will store the original (vfs)
		     * path alongside the temporary load handle
		     * and unload proc ptr.
		     */
		    (*handlePtr) = newLoadHandle;

		    (*unloadProcPtr) = newUnloadProcPtr;
		    return TCL_OK;
		}
		/* 
		 * When we unload this file, we need to divert the 
		 * unloading so we can unload and cleanup the 
		 * temporary file correctly.







>







2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
		     * library which was loaded.  Note that this
		     * does mean that the package list maintained
		     * by 'load' will store the original (vfs)
		     * path alongside the temporary load handle
		     * and unload proc ptr.
		     */
		    (*handlePtr) = newLoadHandle;
		    (*clientDataPtr) = newClientData;
		    (*unloadProcPtr) = newUnloadProcPtr;
		    return TCL_OK;
		}
		/* 
		 * When we unload this file, we need to divert the 
		 * unloading so we can unload and cleanup the 
		 * temporary file correctly.
2680
2681
2682
2683
2684
2685
2686
2687

2688
2689
2690
2691
2692
2693
2694
		     */
		    tvdlPtr->divertedFile = NULL;
		    tvdlPtr->divertedFilesystem = NULL;
		    Tcl_DecrRefCount(copyToPtr);
		}

		copyToPtr = NULL;
		(*handlePtr) = (Tcl_LoadHandle) tvdlPtr;

		(*unloadProcPtr) = &FSUnloadTempFile;
		return retVal;
	    } else {
		/* Cross-platform copy failed */
		Tcl_FSDeleteFile(copyToPtr);
		Tcl_DecrRefCount(copyToPtr);
		return TCL_ERROR;







|
>







2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
		     */
		    tvdlPtr->divertedFile = NULL;
		    tvdlPtr->divertedFilesystem = NULL;
		    Tcl_DecrRefCount(copyToPtr);
		}

		copyToPtr = NULL;
		(*handlePtr) = newLoadHandle;
		(*clientDataPtr) = (ClientData)tvdlPtr;
		(*unloadProcPtr) = &FSUnloadTempFile;
		return retVal;
	    } else {
		/* Cross-platform copy failed */
		Tcl_FSDeleteFile(copyToPtr);
		Tcl_DecrRefCount(copyToPtr);
		return TCL_ERROR;
2973
2974
2975
2976
2977
2978
2979
2980

2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
    CONST char *pattern;	/* Pattern to match against. */
{
    FilesystemRecord *fsRecPtr;
    Tcl_GlobTypeData mountsOnly = { TCL_GLOB_TYPE_MOUNT, 0, NULL, NULL };
    Tcl_Obj *resultPtr = NULL;
    
    /*
     * Call each of the "listMounts" functions in succession.

     * A non-NULL return value indicates the particular function has
     * succeeded.  We call all the functions registered, since we want
     * a list from each filesystems.
     */

    fsRecPtr = FsGetFirstFilesystem();
    while (fsRecPtr != NULL) {
	if (fsRecPtr != &nativeFilesystemRecord) {
	    Tcl_FSMatchInDirectoryProc *proc = 
	                          fsRecPtr->fsPtr->matchInDirectoryProc;







|
>
|
|
|







3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
    CONST char *pattern;	/* Pattern to match against. */
{
    FilesystemRecord *fsRecPtr;
    Tcl_GlobTypeData mountsOnly = { TCL_GLOB_TYPE_MOUNT, 0, NULL, NULL };
    Tcl_Obj *resultPtr = NULL;
    
    /*
     * Call each of the "matchInDirectory" functions in succession, with
     * the specific type information 'mountsOnly'.  A non-NULL return
     * value indicates the particular function has succeeded.  We call
     * all the functions registered, since we want a list from each
     * filesystems.
     */

    fsRecPtr = FsGetFirstFilesystem();
    while (fsRecPtr != NULL) {
	if (fsRecPtr != &nativeFilesystemRecord) {
	    Tcl_FSMatchInDirectoryProc *proc = 
	                          fsRecPtr->fsPtr->matchInDirectoryProc;
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
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

Tcl_PathType
TclGetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr, driveNameRef)
    Tcl_Obj *pathObjPtr;
    Tcl_Filesystem **filesystemPtrPtr;



    int *driveNameLengthPtr;
    Tcl_Obj **driveNameRef;
{
    FilesystemRecord *fsRecPtr;
    int pathLen;
    char *path;
    Tcl_PathType type = TCL_PATH_RELATIVE;
    
    path = Tcl_GetStringFromObj(pathObjPtr, &pathLen);

    /*
     * Call each of the "listVolumes" function in succession, checking
     * whether the given path is an absolute path on any of the volumes
     * returned (this is done by checking whether the path's prefix
     * matches).
     */







|
|
|
>
>
>
|







|







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
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

Tcl_PathType
TclGetPathType(pathPtr, filesystemPtrPtr, driveNameLengthPtr, driveNameRef)
    Tcl_Obj *pathPtr;                   /* Path to determine type for */
    Tcl_Filesystem **filesystemPtrPtr;  /* If absolute path and this is
                                         * non-NULL, then set to the
                                         * filesystem which claims this
                                         * path */  
    int *driveNameLengthPtr;            
    Tcl_Obj **driveNameRef;
{
    FilesystemRecord *fsRecPtr;
    int pathLen;
    char *path;
    Tcl_PathType type = TCL_PATH_RELATIVE;
    
    path = Tcl_GetStringFromObj(pathPtr, &pathLen);

    /*
     * Call each of the "listVolumes" function in succession, checking
     * whether the given path is an absolute path on any of the volumes
     * returned (this is done by checking whether the path's prefix
     * matches).
     */
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
		    /* 
		     * This is VERY bad; the Tcl_FSListVolumesProc
		     * didn't return a valid list.  Set numVolumes to
		     * -1 so that we skip the while loop below and just
		     * return with the current value of 'type'.
		     * 
		     * It would be better if we could signal an error
		     * here (but panic seems a bit excessive).
		     */
		    numVolumes = -1;
		}
		while (numVolumes > 0) {
		    Tcl_Obj *vol;
		    int len;
		    char *strVol;







|







3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
		    /* 
		     * This is VERY bad; the Tcl_FSListVolumesProc
		     * didn't return a valid list.  Set numVolumes to
		     * -1 so that we skip the while loop below and just
		     * return with the current value of 'type'.
		     * 
		     * It would be better if we could signal an error
		     * here (but Tcl_Panic seems a bit excessive).
		     */
		    numVolumes = -1;
		}
		while (numVolumes > 0) {
		    Tcl_Obj *vol;
		    int len;
		    char *strVol;
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
		}
	    }
	}
	fsRecPtr = fsRecPtr->nextPtr;
    }
    
    if (type != TCL_PATH_ABSOLUTE) {
	type = TclpGetNativePathType(pathObjPtr, driveNameLengthPtr, 
				     driveNameRef);
	if ((type == TCL_PATH_ABSOLUTE) && (filesystemPtrPtr != NULL)) {
	    *filesystemPtrPtr = &tclNativeFilesystem;
	}
    }
    return type;
}







|







3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
		}
	    }
	}
	fsRecPtr = fsRecPtr->nextPtr;
    }
    
    if (type != TCL_PATH_ABSOLUTE) {
	type = TclpGetNativePathType(pathPtr, driveNameLengthPtr, 
				     driveNameRef);
	if ((type == TCL_PATH_ABSOLUTE) && (filesystemPtrPtr != NULL)) {
	    *filesystemPtrPtr = &tclNativeFilesystem;
	}
    }
    return type;
}
3555
3556
3557
3558
3559
3560
3561
3562

3563
3564
3565
3566
3567
3568
3569
			cwdStr = Tcl_GetStringFromObj(cwdPtr, &cwdLen);
			if ((cwdLen >= normLen) && (strncmp(normPathStr, 
					cwdStr, (size_t) normLen) == 0)) {
			    /* 
			     * the cwd is inside the directory, so we
			     * perform a 'cd [file dirname $path]'
			     */
			    Tcl_Obj *dirPtr = TclFileDirname(NULL, pathPtr);

			    Tcl_FSChdir(dirPtr);
			    Tcl_DecrRefCount(dirPtr);
			}
		    }
		    Tcl_DecrRefCount(cwdPtr);
		}
	    }







|
>







3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
			cwdStr = Tcl_GetStringFromObj(cwdPtr, &cwdLen);
			if ((cwdLen >= normLen) && (strncmp(normPathStr, 
					cwdStr, (size_t) normLen) == 0)) {
			    /* 
			     * the cwd is inside the directory, so we
			     * perform a 'cd [file dirname $path]'
			     */
			    Tcl_Obj *dirPtr = TclPathPart(NULL, pathPtr, 
							     TCL_PATH_DIRNAME);
			    Tcl_FSChdir(dirPtr);
			    Tcl_DecrRefCount(dirPtr);
			}
		    }
		    Tcl_DecrRefCount(cwdPtr);
		}
	    }
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
 * Side effects:
 *	The object may be converted to a path type.
 *
 *---------------------------------------------------------------------------
 */

Tcl_Filesystem*
Tcl_FSGetFileSystemForPath(pathObjPtr)
    Tcl_Obj* pathObjPtr;
{
    FilesystemRecord *fsRecPtr;
    Tcl_Filesystem* retVal = NULL;
    
    if (pathObjPtr == NULL) {
	panic("Tcl_FSGetFileSystemForPath called with NULL object");
	return NULL;
    }
    
    /* 
     * If the object has a refCount of zero, we reject it.  This
     * is to avoid possible segfaults or nondeterministic memory
     * leaks (i.e. the user doesn't know if they should decrement
     * the ref count on return or not).
     */
    
    if (pathObjPtr->refCount == 0) {
	panic("Tcl_FSGetFileSystemForPath called with object with refCount == 0");
	return NULL;
    }
    
    /* 
     * Check if the filesystem has changed in some way since
     * this object's internal representation was calculated.
     */
    if (TclFSEnsureEpochOk(pathObjPtr, &retVal) != TCL_OK) {
	return NULL;
    }

    /*
     * Call each of the "pathInFilesystem" functions in succession.  A
     * non-return value of -1 indicates the particular function has
     * succeeded.
     */

    fsRecPtr = FsGetFirstFilesystem();
    while ((retVal == NULL) && (fsRecPtr != NULL)) {
	Tcl_FSPathInFilesystemProc *proc = fsRecPtr->fsPtr->pathInFilesystemProc;
	if (proc != NULL) {
	    ClientData clientData = NULL;
	    int ret = (*proc)(pathObjPtr, &clientData);
	    if (ret != -1) {
		/* 
		 * We assume the type of pathObjPtr hasn't been changed 
		 * by the above call to the pathInFilesystemProc.
		 */
		TclFSSetPathDetails(pathObjPtr, fsRecPtr, clientData);
		retVal = fsRecPtr->fsPtr;
	    }
	}
	fsRecPtr = fsRecPtr->nextPtr;
    }

    return retVal;







|
|




|
|










|
|







|














|


|


|







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
 * Side effects:
 *	The object may be converted to a path type.
 *
 *---------------------------------------------------------------------------
 */

Tcl_Filesystem*
Tcl_FSGetFileSystemForPath(pathPtr)
    Tcl_Obj* pathPtr;
{
    FilesystemRecord *fsRecPtr;
    Tcl_Filesystem* retVal = NULL;
    
    if (pathPtr == NULL) {
	Tcl_Panic("Tcl_FSGetFileSystemForPath called with NULL object");
	return NULL;
    }
    
    /* 
     * If the object has a refCount of zero, we reject it.  This
     * is to avoid possible segfaults or nondeterministic memory
     * leaks (i.e. the user doesn't know if they should decrement
     * the ref count on return or not).
     */
    
    if (pathPtr->refCount == 0) {
	Tcl_Panic("Tcl_FSGetFileSystemForPath called with object with refCount == 0");
	return NULL;
    }
    
    /* 
     * Check if the filesystem has changed in some way since
     * this object's internal representation was calculated.
     */
    if (TclFSEnsureEpochOk(pathPtr, &retVal) != TCL_OK) {
	return NULL;
    }

    /*
     * Call each of the "pathInFilesystem" functions in succession.  A
     * non-return value of -1 indicates the particular function has
     * succeeded.
     */

    fsRecPtr = FsGetFirstFilesystem();
    while ((retVal == NULL) && (fsRecPtr != NULL)) {
	Tcl_FSPathInFilesystemProc *proc = fsRecPtr->fsPtr->pathInFilesystemProc;
	if (proc != NULL) {
	    ClientData clientData = NULL;
	    int ret = (*proc)(pathPtr, &clientData);
	    if (ret != -1) {
		/* 
		 * We assume the type of pathPtr hasn't been changed 
		 * by the above call to the pathInFilesystemProc.
		 */
		TclFSSetPathDetails(pathPtr, fsRecPtr, clientData);
		retVal = fsRecPtr->fsPtr;
	    }
	}
	fsRecPtr = fsRecPtr->nextPtr;
    }

    return retVal;
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
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
3729
3730
3731
3732
3733

3734
3735
3736
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
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
 * Side effects:
 *	See Tcl_FSGetInternalRep.
 *
 *---------------------------------------------------------------------------
 */

CONST char *
Tcl_FSGetNativePath(pathObjPtr)
    Tcl_Obj *pathObjPtr;
{
    return (CONST char *)Tcl_FSGetInternalRep(pathObjPtr, &tclNativeFilesystem);
}

/*
 *---------------------------------------------------------------------------
 *
 * NativeCreateNativeRep --
 *
 *      Create a native representation for the given path.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
static ClientData 
NativeCreateNativeRep(pathObjPtr)
    Tcl_Obj* pathObjPtr;
{
    char *nativePathPtr;
    Tcl_DString ds;
    Tcl_Obj* validPathObjPtr;
    int len;
    char *str;






    /* Make sure the normalized path is set */
    validPathObjPtr = Tcl_FSGetNormalizedPath(NULL, pathObjPtr);



    str = Tcl_GetStringFromObj(validPathObjPtr, &len);
#ifdef __WIN32__
    Tcl_WinUtfToTChar(str, len, &ds);
    if (tclWinProcs->useWide) {
	len = Tcl_DStringLength(&ds) + sizeof(WCHAR);
    } else {
	len = Tcl_DStringLength(&ds) + sizeof(char);
    }
#else
    Tcl_UtfToExternalDString(NULL, str, len, &ds);
    len = Tcl_DStringLength(&ds) + sizeof(char);
#endif

    nativePathPtr = ckalloc((unsigned) len);
    memcpy((VOID*)nativePathPtr, (VOID*)Tcl_DStringValue(&ds), (size_t) len);
	  
    Tcl_DStringFree(&ds);
    return (ClientData)nativePathPtr;
}

/*
 *---------------------------------------------------------------------------
 *
 * TclpNativeToNormalized --
 *
 *      Convert native format to a normalized path object, with refCount
 *      of zero.





 *
 * Results:
 *      A valid normalized path.
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj* 
TclpNativeToNormalized(clientData)
    ClientData clientData;
{
    Tcl_DString ds;
    Tcl_Obj *objPtr;
    CONST char *copy;
    int len;
    
#ifdef __WIN32__


    Tcl_WinTCharToUtf((CONST char*)clientData, -1, &ds);
#else

    Tcl_ExternalToUtfDString(NULL, (CONST char*)clientData, -1, &ds);
#endif
    
    copy = Tcl_DStringValue(&ds);
    len = Tcl_DStringLength(&ds);

#ifdef __WIN32__
    /* 
     * Certain native path representations on Windows have this special
     * prefix to indicate that they are to be treated specially.  For
     * example extremely long paths, or symlinks 
     */
    if (*copy == '\\') {
        if (0 == strncmp(copy,"\\??\\",4)) {
	    copy += 4;
	    len -= 4;
	} else if (0 == strncmp(copy,"\\\\?\\",4)) {
	    copy += 4;
	    len -= 4;
	}








    }
#endif

    objPtr = Tcl_NewStringObj(copy,len);
    Tcl_DStringFree(&ds);
    
    return objPtr;







|
|

|


















|
|



|


>

>
>
>
>
|
|
>
|
>
|











>














>
>
>
>
>















<



>
>


>




















>
>
>
>
>
>
>
>







3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076

4077
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
4116
4117
4118
4119
 * Side effects:
 *	See Tcl_FSGetInternalRep.
 *
 *---------------------------------------------------------------------------
 */

CONST char *
Tcl_FSGetNativePath(pathPtr)
    Tcl_Obj *pathPtr;
{
    return (CONST char *)Tcl_FSGetInternalRep(pathPtr, &tclNativeFilesystem);
}

/*
 *---------------------------------------------------------------------------
 *
 * NativeCreateNativeRep --
 *
 *      Create a native representation for the given path.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
static ClientData 
NativeCreateNativeRep(pathPtr)
    Tcl_Obj* pathPtr;
{
    char *nativePathPtr;
    Tcl_DString ds;
    Tcl_Obj* validPathPtr;
    int len;
    char *str;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);

    if (tsdPtr->cwdClientData != NULL) {
        /* The cwd is native */
	validPathPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr);
    } else {
	/* Make sure the normalized path is set */
	validPathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr);
	Tcl_IncrRefCount(validPathPtr);
    }

    str = Tcl_GetStringFromObj(validPathPtr, &len);
#ifdef __WIN32__
    Tcl_WinUtfToTChar(str, len, &ds);
    if (tclWinProcs->useWide) {
	len = Tcl_DStringLength(&ds) + sizeof(WCHAR);
    } else {
	len = Tcl_DStringLength(&ds) + sizeof(char);
    }
#else
    Tcl_UtfToExternalDString(NULL, str, len, &ds);
    len = Tcl_DStringLength(&ds) + sizeof(char);
#endif
    Tcl_DecrRefCount(validPathPtr);
    nativePathPtr = ckalloc((unsigned) len);
    memcpy((VOID*)nativePathPtr, (VOID*)Tcl_DStringValue(&ds), (size_t) len);
	  
    Tcl_DStringFree(&ds);
    return (ClientData)nativePathPtr;
}

/*
 *---------------------------------------------------------------------------
 *
 * TclpNativeToNormalized --
 *
 *      Convert native format to a normalized path object, with refCount
 *      of zero.
 *      
 *      Currently assumes all native paths are actually normalized
 *      already, so if the path given is not normalized this will
 *      actually just convert to a valid string path, but not
 *      necessarily a normalized one.
 *
 * Results:
 *      A valid normalized path.
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj* 
TclpNativeToNormalized(clientData)
    ClientData clientData;
{
    Tcl_DString ds;
    Tcl_Obj *objPtr;

    int len;
    
#ifdef __WIN32__
    char *copy;
    char *p;
    Tcl_WinTCharToUtf((CONST char*)clientData, -1, &ds);
#else
    CONST char *copy;
    Tcl_ExternalToUtfDString(NULL, (CONST char*)clientData, -1, &ds);
#endif
    
    copy = Tcl_DStringValue(&ds);
    len = Tcl_DStringLength(&ds);

#ifdef __WIN32__
    /* 
     * Certain native path representations on Windows have this special
     * prefix to indicate that they are to be treated specially.  For
     * example extremely long paths, or symlinks 
     */
    if (*copy == '\\') {
        if (0 == strncmp(copy,"\\??\\",4)) {
	    copy += 4;
	    len -= 4;
	} else if (0 == strncmp(copy,"\\\\?\\",4)) {
	    copy += 4;
	    len -= 4;
	}
    }
    /* 
     * Ensure we are using forward slashes only.
     */
    for (p = copy; *p != '\0'; p++) {
	if (*p == '\\') {
	    *p = '/';
	}
    }
#endif

    objPtr = Tcl_NewStringObj(copy,len);
    Tcl_DStringFree(&ds);
    
    return objPtr;
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
3843
3844
3845
3846
3847
3848
 *
 *---------------------------------------------------------------------------
 */
ClientData 
TclNativeDupInternalRep(clientData)
    ClientData clientData;
{
    ClientData copy;
    size_t len;

    if (clientData == NULL) {
	return NULL;
    }

#ifdef __WIN32__
    if (tclWinProcs->useWide) {
	/* unicode representation when running on NT/2K/XP */
	len = sizeof(WCHAR) + (wcslen((CONST WCHAR*)clientData) * sizeof(WCHAR));
    } else {
	/* ansi representation when running on 95/98/ME */
	len = sizeof(char) + (strlen((CONST char*)clientData) * sizeof(char));
    }
#else
    /* ansi representation when running on Unix/MacOS */
    len = sizeof(char) + (strlen((CONST char*)clientData) * sizeof(char));
#endif
    
    copy = (ClientData) ckalloc(len);
    memcpy((VOID*)copy, (VOID*)clientData, len);
    return copy;
}

/*
 *---------------------------------------------------------------------------
 *
 * NativeFreeInternalRep --
 *







|



















|

|







4136
4137
4138
4139
4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150
4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
 *
 *---------------------------------------------------------------------------
 */
ClientData 
TclNativeDupInternalRep(clientData)
    ClientData clientData;
{
    char *copy;
    size_t len;

    if (clientData == NULL) {
	return NULL;
    }

#ifdef __WIN32__
    if (tclWinProcs->useWide) {
	/* unicode representation when running on NT/2K/XP */
	len = sizeof(WCHAR) + (wcslen((CONST WCHAR*)clientData) * sizeof(WCHAR));
    } else {
	/* ansi representation when running on 95/98/ME */
	len = sizeof(char) + (strlen((CONST char*)clientData) * sizeof(char));
    }
#else
    /* ansi representation when running on Unix/MacOS */
    len = sizeof(char) + (strlen((CONST char*)clientData) * sizeof(char));
#endif
    
    copy = (char *) ckalloc(len);
    memcpy((VOID*)copy, (VOID*)clientData, len);
    return (ClientData)copy;
}

/*
 *---------------------------------------------------------------------------
 *
 * NativeFreeInternalRep --
 *
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
3908
3909
3910
 *
 * Side effects:
 *	The object may be converted to a path type.
 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj*
Tcl_FSFileSystemInfo(pathObjPtr)
    Tcl_Obj* pathObjPtr;
{
    Tcl_Obj *resPtr;
    Tcl_FSFilesystemPathTypeProc *proc;
    Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathObjPtr);
    
    if (fsPtr == NULL) {
	return NULL;
    }
    
    resPtr = Tcl_NewListObj(0,NULL);
    
    Tcl_ListObjAppendElement(NULL, resPtr, 
			     Tcl_NewStringObj(fsPtr->typeName,-1));

    proc = fsPtr->filesystemPathTypeProc;
    if (proc != NULL) {
	Tcl_Obj *typePtr = (*proc)(pathObjPtr);
	if (typePtr != NULL) {
	    Tcl_ListObjAppendElement(NULL, resPtr, typePtr);
	}
    }
    
    return resPtr;
}







|
|



|












|







4202
4203
4204
4205
4206
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
 *
 * Side effects:
 *	The object may be converted to a path type.
 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj*
Tcl_FSFileSystemInfo(pathPtr)
    Tcl_Obj* pathPtr;
{
    Tcl_Obj *resPtr;
    Tcl_FSFilesystemPathTypeProc *proc;
    Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr);
    
    if (fsPtr == NULL) {
	return NULL;
    }
    
    resPtr = Tcl_NewListObj(0,NULL);
    
    Tcl_ListObjAppendElement(NULL, resPtr, 
			     Tcl_NewStringObj(fsPtr->typeName,-1));

    proc = fsPtr->filesystemPathTypeProc;
    if (proc != NULL) {
	Tcl_Obj *typePtr = (*proc)(pathPtr);
	if (typePtr != NULL) {
	    Tcl_ListObjAppendElement(NULL, resPtr, typePtr);
	}
    }
    
    return resPtr;
}
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
 *
 * Side effects:
 *	The path object may be converted to a path type.
 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj*
Tcl_FSPathSeparator(pathObjPtr)
    Tcl_Obj* pathObjPtr;
{
    Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathObjPtr);
    
    if (fsPtr == NULL) {
	return NULL;
    }
    if (fsPtr->filesystemSeparatorProc != NULL) {
	return (*fsPtr->filesystemSeparatorProc)(pathObjPtr);
    }
    
    return NULL;
}

/*
 *---------------------------------------------------------------------------







|
|

|





|







4248
4249
4250
4251
4252
4253
4254
4255
4256
4257
4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
 *
 * Side effects:
 *	The path object may be converted to a path type.
 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj*
Tcl_FSPathSeparator(pathPtr)
    Tcl_Obj* pathPtr;
{
    Tcl_Filesystem *fsPtr = Tcl_FSGetFileSystemForPath(pathPtr);
    
    if (fsPtr == NULL) {
	return NULL;
    }
    if (fsPtr->filesystemSeparatorProc != NULL) {
	return (*fsPtr->filesystemSeparatorProc)(pathPtr);
    }
    
    return NULL;
}

/*
 *---------------------------------------------------------------------------
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
static Tcl_Obj*
NativeFilesystemSeparator(pathObjPtr)
    Tcl_Obj* pathObjPtr;
{
    char *separator = NULL; /* lint */
    switch (tclPlatform) {
	case TCL_PLATFORM_UNIX:
	    separator = "/";
	    break;
	case TCL_PLATFORM_WINDOWS:







|
|







4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
static Tcl_Obj*
NativeFilesystemSeparator(pathPtr)
    Tcl_Obj* pathPtr;
{
    char *separator = NULL; /* lint */
    switch (tclPlatform) {
	case TCL_PLATFORM_UNIX:
	    separator = "/";
	    break;
	case TCL_PLATFORM_WINDOWS:
Changes to generic/tclIndexObj.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclIndexObj.c --
 *
 *	This file implements objects of type "index".  This object type
 *	is used to lookup a keyword in a table of valid values and cache
 *	the index of the matching entry.
 *
 * Copyright (c) 1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclIndexObj.c,v 1.16 2002/02/28 05:11:25 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * Prototypes for procedures defined later in this file:












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclIndexObj.c --
 *
 *	This file implements objects of type "index".  This object type
 *	is used to lookup a keyword in a table of valid values and cache
 *	the index of the matching entry.
 *
 * Copyright (c) 1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclIndexObj.c,v 1.16.4.1 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * Prototypes for procedures defined later in this file:
267
268
269
270
271
272
273


274
275
276
277
278
279
280
281

    error:
    if (interp != NULL) {
	/*
	 * Produce a fancy error message.
	 */
	int count;


	resultPtr = Tcl_GetObjResult(interp);
	Tcl_AppendStringsToObj(resultPtr,
		(numAbbrev > 1) ? "ambiguous " : "bad ", msg, " \"",
		key, "\": must be ", STRING_AT(tablePtr,offset,0), (char*)NULL);
	for (entryPtr = NEXT_ENTRY(tablePtr, offset), count = 0;
		*entryPtr != NULL;
		entryPtr = NEXT_ENTRY(entryPtr, offset), count++) {
	    if (*NEXT_ENTRY(entryPtr, offset) == NULL) {







>
>
|







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

    error:
    if (interp != NULL) {
	/*
	 * Produce a fancy error message.
	 */
	int count;

	TclNewObj(resultPtr);
	Tcl_SetObjResult(interp, resultPtr);
	Tcl_AppendStringsToObj(resultPtr,
		(numAbbrev > 1) ? "ambiguous " : "bad ", msg, " \"",
		key, "\": must be ", STRING_AT(tablePtr,offset,0), (char*)NULL);
	for (entryPtr = NEXT_ENTRY(tablePtr, offset), count = 0;
		*entryPtr != NULL;
		entryPtr = NEXT_ENTRY(entryPtr, offset), count++) {
	    if (*NEXT_ENTRY(entryPtr, offset) == NULL) {
446
447
448
449
450
451
452

453
454
455
456
457
458
459
460
					 * leading objects in objv. The
					 * message may be NULL. */
{
    Tcl_Obj *objPtr;
    int i;
    register IndexRep *indexRep;


    objPtr = Tcl_GetObjResult(interp);
    Tcl_AppendToObj(objPtr, "wrong # args: should be \"", -1);
    for (i = 0; i < objc; i++) {
	/*
	 * If the object is an index type use the index table which allows
	 * for the correct error message even if the subcommand was
	 * abbreviated.  Otherwise, just use the string rep.
	 */







>
|







448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
					 * leading objects in objv. The
					 * message may be NULL. */
{
    Tcl_Obj *objPtr;
    int i;
    register IndexRep *indexRep;

    TclNewObj(objPtr);
    Tcl_SetObjResult(interp, objPtr);
    Tcl_AppendToObj(objPtr, "wrong # args: should be \"", -1);
    for (i = 0; i < objc; i++) {
	/*
	 * If the object is an index type use the index table which allows
	 * for the correct error message even if the subcommand was
	 * abbreviated.  Otherwise, just use the string rep.
	 */
Changes to generic/tclInt.decls.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#
# Copyright (c) 1998-1999 by Scriptics Corporation.
# Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# RCS: @(#) $Id: tclInt.decls,v 1.61.2.2 2003/09/05 23:08:06 dgp Exp $

library tcl

# Define the unsupported generic interfaces.

interface tclInt








|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#
# Copyright (c) 1998-1999 by Scriptics Corporation.
# Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# RCS: @(#) $Id: tclInt.decls,v 1.61.2.3 2004/02/07 05:48:01 dgp Exp $

library tcl

# Define the unsupported generic interfaces.

interface tclInt

71
72
73
74
75
76
77

78
79
80
81

82
83
84
85
86
87
88
}
declare 11 generic {
    void TclDeleteCompiledLocalVars(Interp *iPtr, CallFrame *framePtr)
}
declare 12 generic {
    void TclDeleteVars(Interp *iPtr, Tcl_HashTable *tablePtr)
}

declare 13 generic {
    int TclDoGlob(Tcl_Interp *interp, char *separators,
	    Tcl_DString *headPtr, char *tail, Tcl_GlobTypeData *types)
}

declare 14 generic {
    void TclDumpMemoryInfo(FILE *outFile)
}
# Removed in 8.1:
#  declare 15 generic {
#      void TclExpandParseValue(ParseValue *pvPtr, int needed)
#  }







>
|
|
|
<
>







71
72
73
74
75
76
77
78
79
80
81

82
83
84
85
86
87
88
89
}
declare 11 generic {
    void TclDeleteCompiledLocalVars(Interp *iPtr, CallFrame *framePtr)
}
declare 12 generic {
    void TclDeleteVars(Interp *iPtr, Tcl_HashTable *tablePtr)
}
# Removed in 8.5
#declare 13 generic {
#    int TclDoGlob(Tcl_Interp *interp, char *separators,
#	    Tcl_DString *headPtr, char *tail, Tcl_GlobTypeData *types)

#}
declare 14 generic {
    void TclDumpMemoryInfo(FILE *outFile)
}
# Removed in 8.1:
#  declare 15 generic {
#      void TclExpandParseValue(ParseValue *pvPtr, int needed)
#  }
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#	    int localIndex, Tcl_Obj *elemPtr, int flags)
#}
# Replaced by char *TclGetEnv(CONST char *name, Tcl_DString *valuePtr) in 8.1:
#  declare 30 generic {
#      char *TclGetEnv(CONST char *name)
#  }
declare 31 generic {
    char *TclGetExtension(char *name)
}
declare 32 generic {
    int TclGetFrame(Tcl_Interp *interp, CONST char *str,
	    CallFrame **framePtrPtr)
}
declare 33 generic {
    TclCmdProcType TclGetInterpProc(void)







|







137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#	    int localIndex, Tcl_Obj *elemPtr, int flags)
#}
# Replaced by char *TclGetEnv(CONST char *name, Tcl_DString *valuePtr) in 8.1:
#  declare 30 generic {
#      char *TclGetEnv(CONST char *name)
#  }
declare 31 generic {
    CONST char *TclGetExtension(CONST char *name)
}
declare 32 generic {
    int TclGetFrame(Tcl_Interp *interp, CONST char *str,
	    CallFrame **framePtrPtr)
}
declare 33 generic {
    TclCmdProcType TclGetInterpProc(void)
523
524
525
526
527
528
529
530
531
532

533
534
535
536
537
538
539
declare 133 generic {
    struct tm *TclpGetDate(TclpTime_t time, int useGMT)
}
declare 134 generic {
    size_t TclpStrftime(char *s, size_t maxsize, CONST char *format,
	    CONST struct tm *t, int useGMT)
}
declare 135 generic {
    int TclpCheckStackSpace(void)
}


# Added in 8.1:

#declare 137 generic {
#   int TclpChdir(CONST char *dirName)
#}
declare 138 generic {







|
|
<
>







524
525
526
527
528
529
530
531
532

533
534
535
536
537
538
539
540
declare 133 generic {
    struct tm *TclpGetDate(TclpTime_t time, int useGMT)
}
declare 134 generic {
    size_t TclpStrftime(char *s, size_t maxsize, CONST char *format,
	    CONST struct tm *t, int useGMT)
}
#declare 135 generic {
#    int TclpCheckStackSpace(void)

#}

# Added in 8.1:

#declare 137 generic {
#   int TclpChdir(CONST char *dirName)
#}
declare 138 generic {
721
722
723
724
725
726
727









728
729
730
731
732
733
734

declare 178 generic {
    void Tcl_SetStartupScript(Tcl_Obj *pathPtr, CONST char* encodingName)
}
declare 179 generic {
    Tcl_Obj *Tcl_GetStartupScript(CONST char **encodingNamePtr)
}









##############################################################################

# Define the platform specific internal Tcl interface. These functions are
# only available on the designated platform.

interface tclIntPlat








>
>
>
>
>
>
>
>
>







722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744

declare 178 generic {
    void Tcl_SetStartupScript(Tcl_Obj *pathPtr, CONST char* encodingName)
}
declare 179 generic {
    Tcl_Obj *Tcl_GetStartupScript(CONST char **encodingNamePtr)
}

# Allocate lists without copying arrays
declare 180 generic {
    Tcl_Obj *TclNewListObjDirect(int objc, Tcl_Obj **objv)
}
declare 181 generic {
    Tcl_Obj *TclDbNewListObjDirect(int objc, Tcl_Obj **objv,
	    CONST char *file, int line)
}
##############################################################################

# Define the platform specific internal Tcl interface. These functions are
# only available on the designated platform.

interface tclIntPlat

Changes to generic/tclInt.h.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 * Copyright (c) 1994-1998 Sun Microsystems, Inc.
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 * Copyright (c) 2001, 2002 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclInt.h,v 1.127.2.5 2003/10/16 02:28:02 dgp Exp $
 */

#ifndef _TCLINT
#define _TCLINT

/*
 * Common include files needed by most of the Tcl source files are







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 * Copyright (c) 1994-1998 Sun Microsystems, Inc.
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 * Copyright (c) 2001, 2002 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclInt.h,v 1.127.2.6 2004/02/07 05:48:01 dgp Exp $
 */

#ifndef _TCLINT
#define _TCLINT

/*
 * Common include files needed by most of the Tcl source files are
1479
1480
1481
1482
1483
1484
1485
















1486
1487
1488
1489
1490
1491
1492

typedef struct List {
    int maxElemCount;		/* Total number of element array slots. */
    int elemCount;		/* Current number of list elements. */
    Tcl_Obj **elements;		/* Array of pointers to element objects. */
} List;


















/*
 * The following types are used for getting and storing platform-specific
 * file attributes in tclFCmd.c and the various platform-versions of
 * that file. This is done to have as much common code as possible
 * in the file attributes code. For more information about the callbacks,
 * see TclFileAttrsCmd in tclFCmd.c.







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







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

typedef struct List {
    int maxElemCount;		/* Total number of element array slots. */
    int elemCount;		/* Current number of list elements. */
    Tcl_Obj **elements;		/* Array of pointers to element objects. */
} List;

/*
 *----------------------------------------------------------------
 * Data structures related to the filesystem internals
 *----------------------------------------------------------------
 */


/* 
 * The version_2 filesystem is private to Tcl.  As and when these
 * changes have been thoroughly tested and investigated a new public
 * filesystem interface will be released.  The aim is more versatile
 * virtual filesystem interfaces, more efficiency in 'path' manipulation
 * and usage, and cleaner filesystem code internally.
 */
#define TCL_FILESYSTEM_VERSION_2	((Tcl_FSVersion) 0x2)
typedef ClientData (TclFSGetCwdProc2) _ANSI_ARGS_((ClientData clientData));

/*
 * The following types are used for getting and storing platform-specific
 * file attributes in tclFCmd.c and the various platform-versions of
 * that file. This is done to have as much common code as possible
 * in the file attributes code. For more information about the callbacks,
 * see TclFileAttrsCmd in tclFCmd.c.
1520
1521
1522
1523
1524
1525
1526







1527
1528
1529
1530
1531
1532
1533
 * or'ed combination of the following values:
 */

#define TCL_GLOBMODE_NO_COMPLAIN      1
#define TCL_GLOBMODE_JOIN             2
#define TCL_GLOBMODE_DIR              4
#define TCL_GLOBMODE_TAILS            8








/*
 *----------------------------------------------------------------
 * Data structures related to obsolete filesystem hooks
 *----------------------------------------------------------------
 */








>
>
>
>
>
>
>







1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
 * or'ed combination of the following values:
 */

#define TCL_GLOBMODE_NO_COMPLAIN      1
#define TCL_GLOBMODE_JOIN             2
#define TCL_GLOBMODE_DIR              4
#define TCL_GLOBMODE_TAILS            8

typedef enum Tcl_PathPart {
    TCL_PATH_DIRNAME,
    TCL_PATH_TAIL,	
    TCL_PATH_EXTENSION,
    TCL_PATH_ROOT
} Tcl_PathPart;

/*
 *----------------------------------------------------------------
 * Data structures related to obsolete filesystem hooks
 *----------------------------------------------------------------
 */

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
						   Tcl_Obj* listPtr,
						   Tcl_Obj* argPtr ));
EXTERN Tcl_Obj *	TclLindexFlat _ANSI_ARGS_((Tcl_Interp* interp,
						   Tcl_Obj* listPtr,
						   int indexCount,
						   Tcl_Obj *CONST indexArray[]
						   ));







EXTERN Tcl_Obj *	TclLsetList _ANSI_ARGS_((Tcl_Interp* interp,
						 Tcl_Obj* listPtr,
						 Tcl_Obj* indexPtr,
						 Tcl_Obj* valuePtr  
						 ));
EXTERN Tcl_Obj *	TclLsetFlat _ANSI_ARGS_((Tcl_Interp* interp,
						 Tcl_Obj* listPtr,
						 int indexCount,
						 Tcl_Obj *CONST indexArray[],
						 Tcl_Obj* valuePtr
						 ));




EXTERN int              TclParseBackslash _ANSI_ARGS_((CONST char *src,
                            int numBytes, int *readPtr, char *dst));
EXTERN int              TclParseExpr _ANSI_ARGS_((Tcl_Interp *interp,
			    CONST char *string, int numBytes,
			    int useInternalTokens, Tcl_Parse *parsePtr));
EXTERN int		TclParseHex _ANSI_ARGS_((CONST char *src, int numBytes,
                            Tcl_UniChar *resultPtr));
EXTERN int		TclParseInteger _ANSI_ARGS_((CONST char *string,
			    int numBytes));
Tcl_Token *		TclParseScript _ANSI_ARGS_((CONST char *script,
			    int numBytes, int flags,
			    Tcl_Token **lastTokenPtrPtr, CONST char **termPtr));
EXTERN int		TclParseWhiteSpace _ANSI_ARGS_((CONST char *src,
			    int numBytes, Tcl_Parse *parsePtr, char *typePtr));


EXTERN int		TclpObjAccess _ANSI_ARGS_((Tcl_Obj *filename,
			    int mode));
EXTERN int              TclpObjLstat _ANSI_ARGS_((Tcl_Obj *pathPtr, 
			    Tcl_StatBuf *buf));
EXTERN int		TclpCheckStackSpace _ANSI_ARGS_((void));
EXTERN Tcl_Obj*         TclpTempFileName _ANSI_ARGS_((void));
EXTERN Tcl_Obj*         TclNewFSPathObj _ANSI_ARGS_((Tcl_Obj *dirPtr, 







>
>
>
>
>
>
>











>
>
>
>














>
>







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
						   Tcl_Obj* listPtr,
						   Tcl_Obj* argPtr ));
EXTERN Tcl_Obj *	TclLindexFlat _ANSI_ARGS_((Tcl_Interp* interp,
						   Tcl_Obj* listPtr,
						   int indexCount,
						   Tcl_Obj *CONST indexArray[]
						   ));
EXTERN int              TclLoadFile _ANSI_ARGS_((Tcl_Interp* interp,
			    Tcl_Obj *pathPtr, int symc,
			    CONST char *symbols[],
			    Tcl_PackageInitProc **procPtrs[],
			    Tcl_LoadHandle *handlePtr,
			    ClientData *clientDataPtr,
			    Tcl_FSUnloadFileProc **unloadProcPtr));
EXTERN Tcl_Obj *	TclLsetList _ANSI_ARGS_((Tcl_Interp* interp,
						 Tcl_Obj* listPtr,
						 Tcl_Obj* indexPtr,
						 Tcl_Obj* valuePtr  
						 ));
EXTERN Tcl_Obj *	TclLsetFlat _ANSI_ARGS_((Tcl_Interp* interp,
						 Tcl_Obj* listPtr,
						 int indexCount,
						 Tcl_Obj *CONST indexArray[],
						 Tcl_Obj* valuePtr
						 ));
EXTERN int		TclMergeReturnOptions _ANSI_ARGS_((Tcl_Interp *interp,
			    int objc, Tcl_Obj *CONST objv[],
			    Tcl_Obj **optionsPtrPtr, int *codePtr,
			    int *levelPtr));
EXTERN int              TclParseBackslash _ANSI_ARGS_((CONST char *src,
                            int numBytes, int *readPtr, char *dst));
EXTERN int              TclParseExpr _ANSI_ARGS_((Tcl_Interp *interp,
			    CONST char *string, int numBytes,
			    int useInternalTokens, Tcl_Parse *parsePtr));
EXTERN int		TclParseHex _ANSI_ARGS_((CONST char *src, int numBytes,
                            Tcl_UniChar *resultPtr));
EXTERN int		TclParseInteger _ANSI_ARGS_((CONST char *string,
			    int numBytes));
Tcl_Token *		TclParseScript _ANSI_ARGS_((CONST char *script,
			    int numBytes, int flags,
			    Tcl_Token **lastTokenPtrPtr, CONST char **termPtr));
EXTERN int		TclParseWhiteSpace _ANSI_ARGS_((CONST char *src,
			    int numBytes, Tcl_Parse *parsePtr, char *typePtr));
EXTERN int		TclProcessReturn _ANSI_ARGS_((Tcl_Interp *interp,
			    int code, int level, Tcl_Obj *returnOpts));
EXTERN int		TclpObjAccess _ANSI_ARGS_((Tcl_Obj *filename,
			    int mode));
EXTERN int              TclpObjLstat _ANSI_ARGS_((Tcl_Obj *pathPtr, 
			    Tcl_StatBuf *buf));
EXTERN int		TclpCheckStackSpace _ANSI_ARGS_((void));
EXTERN Tcl_Obj*         TclpTempFileName _ANSI_ARGS_((void));
EXTERN Tcl_Obj*         TclNewFSPathObj _ANSI_ARGS_((Tcl_Obj *dirPtr, 
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
EXTERN int              TclpObjNormalizePath _ANSI_ARGS_((Tcl_Interp *interp, 
			    Tcl_Obj *pathPtr, int nextCheckpoint));
EXTERN int		TclpObjCreateDirectory _ANSI_ARGS_((Tcl_Obj *pathPtr));
EXTERN void             TclpNativeJoinPath _ANSI_ARGS_((Tcl_Obj *prefix, 
							char *joining));
EXTERN Tcl_Obj*         TclpNativeSplitPath _ANSI_ARGS_((Tcl_Obj *pathPtr, 
							 int *lenPtr));
EXTERN Tcl_PathType     TclpGetNativePathType _ANSI_ARGS_((Tcl_Obj *pathObjPtr,
			    int *driveNameLengthPtr, Tcl_Obj **driveNameRef));
EXTERN int 		TclCrossFilesystemCopy _ANSI_ARGS_((Tcl_Interp *interp, 
			    Tcl_Obj *source, Tcl_Obj *target));
EXTERN int		TclpObjDeleteFile _ANSI_ARGS_((Tcl_Obj *pathPtr));
EXTERN int		TclpObjCopyDirectory _ANSI_ARGS_((Tcl_Obj *srcPathPtr, 
				Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr));
EXTERN int		TclpObjCopyFile _ANSI_ARGS_((Tcl_Obj *srcPathPtr, 
				Tcl_Obj *destPathPtr));
EXTERN int		TclpObjRemoveDirectory _ANSI_ARGS_((Tcl_Obj *pathPtr, 
				int recursive, Tcl_Obj **errorPtr));
EXTERN int		TclpObjRenameFile _ANSI_ARGS_((Tcl_Obj *srcPathPtr, 
				Tcl_Obj *destPathPtr));
EXTERN int		TclpMatchInDirectory _ANSI_ARGS_((Tcl_Interp *interp, 
			        Tcl_Obj *resultPtr, Tcl_Obj *pathPtr, 
				CONST char *pattern, Tcl_GlobTypeData *types));
EXTERN Tcl_Obj*		TclpObjGetCwd _ANSI_ARGS_((Tcl_Interp *interp));

EXTERN Tcl_Obj*		TclpObjLink _ANSI_ARGS_((Tcl_Obj *pathPtr, 
				Tcl_Obj *toPtr, int linkType));
EXTERN int		TclpObjChdir _ANSI_ARGS_((Tcl_Obj *pathPtr));
EXTERN Tcl_Obj*         TclFileDirname _ANSI_ARGS_((Tcl_Interp *interp, 
						    Tcl_Obj*pathPtr));
EXTERN int		TclpObjStat _ANSI_ARGS_((Tcl_Obj *pathPtr, Tcl_StatBuf *buf));

EXTERN Tcl_Channel	TclpOpenFileChannel _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *pathPtr, int mode,
			    int permissions));
EXTERN void		TclpCutFileChannel _ANSI_ARGS_((Tcl_Channel chan));
EXTERN void		TclpCutSockChannel _ANSI_ARGS_((Tcl_Channel chan));
EXTERN void		TclpSpliceFileChannel _ANSI_ARGS_((Tcl_Channel chan));
EXTERN void		TclpSpliceSockChannel _ANSI_ARGS_((Tcl_Channel chan));







|















|
>



|
|
|
>







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
EXTERN int              TclpObjNormalizePath _ANSI_ARGS_((Tcl_Interp *interp, 
			    Tcl_Obj *pathPtr, int nextCheckpoint));
EXTERN int		TclpObjCreateDirectory _ANSI_ARGS_((Tcl_Obj *pathPtr));
EXTERN void             TclpNativeJoinPath _ANSI_ARGS_((Tcl_Obj *prefix, 
							char *joining));
EXTERN Tcl_Obj*         TclpNativeSplitPath _ANSI_ARGS_((Tcl_Obj *pathPtr, 
							 int *lenPtr));
EXTERN Tcl_PathType     TclpGetNativePathType _ANSI_ARGS_((Tcl_Obj *pathPtr,
			    int *driveNameLengthPtr, Tcl_Obj **driveNameRef));
EXTERN int 		TclCrossFilesystemCopy _ANSI_ARGS_((Tcl_Interp *interp, 
			    Tcl_Obj *source, Tcl_Obj *target));
EXTERN int		TclpObjDeleteFile _ANSI_ARGS_((Tcl_Obj *pathPtr));
EXTERN int		TclpObjCopyDirectory _ANSI_ARGS_((Tcl_Obj *srcPathPtr, 
				Tcl_Obj *destPathPtr, Tcl_Obj **errorPtr));
EXTERN int		TclpObjCopyFile _ANSI_ARGS_((Tcl_Obj *srcPathPtr, 
				Tcl_Obj *destPathPtr));
EXTERN int		TclpObjRemoveDirectory _ANSI_ARGS_((Tcl_Obj *pathPtr, 
				int recursive, Tcl_Obj **errorPtr));
EXTERN int		TclpObjRenameFile _ANSI_ARGS_((Tcl_Obj *srcPathPtr, 
				Tcl_Obj *destPathPtr));
EXTERN int		TclpMatchInDirectory _ANSI_ARGS_((Tcl_Interp *interp, 
			        Tcl_Obj *resultPtr, Tcl_Obj *pathPtr, 
				CONST char *pattern, Tcl_GlobTypeData *types));
EXTERN ClientData	TclpGetNativeCwd _ANSI_ARGS_((ClientData clientData));
EXTERN Tcl_FSDupInternalRepProc TclNativeDupInternalRep;
EXTERN Tcl_Obj*		TclpObjLink _ANSI_ARGS_((Tcl_Obj *pathPtr, 
				Tcl_Obj *toPtr, int linkType));
EXTERN int		TclpObjChdir _ANSI_ARGS_((Tcl_Obj *pathPtr));
EXTERN Tcl_Obj*         TclPathPart _ANSI_ARGS_((Tcl_Interp *interp, 
				Tcl_Obj *pathPtr, Tcl_PathPart portion));
EXTERN int		TclpObjStat _ANSI_ARGS_((Tcl_Obj *pathPtr, 
						 Tcl_StatBuf *buf));
EXTERN Tcl_Channel	TclpOpenFileChannel _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_Obj *pathPtr, int mode,
			    int permissions));
EXTERN void		TclpCutFileChannel _ANSI_ARGS_((Tcl_Channel chan));
EXTERN void		TclpCutSockChannel _ANSI_ARGS_((Tcl_Channel chan));
EXTERN void		TclpSpliceFileChannel _ANSI_ARGS_((Tcl_Channel chan));
EXTERN void		TclpSpliceSockChannel _ANSI_ARGS_((Tcl_Channel chan));
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
			    Tcl_Token *tokenPtr, int count,
			    int *tokensLeftPtr, int flags));
EXTERN void		TclTransferResult _ANSI_ARGS_((Tcl_Interp *sourceInterp,
			    int result, Tcl_Interp *targetInterp));
EXTERN Tcl_Obj*         TclpNativeToNormalized 
                            _ANSI_ARGS_((ClientData clientData));
EXTERN Tcl_Obj*	        TclpFilesystemPathType
					_ANSI_ARGS_((Tcl_Obj* pathObjPtr));
EXTERN Tcl_PackageInitProc* TclpFindSymbol _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_LoadHandle loadHandle, CONST char *symbol));
EXTERN int              TclpDlopen _ANSI_ARGS_((Tcl_Interp *interp, 
			    Tcl_Obj *pathPtr, 
	                    Tcl_LoadHandle *loadHandle, 
		            Tcl_FSUnloadFileProc **unloadProcPtr));
EXTERN int              TclpUtime _ANSI_ARGS_((Tcl_Obj *pathPtr,







|







1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
			    Tcl_Token *tokenPtr, int count,
			    int *tokensLeftPtr, int flags));
EXTERN void		TclTransferResult _ANSI_ARGS_((Tcl_Interp *sourceInterp,
			    int result, Tcl_Interp *targetInterp));
EXTERN Tcl_Obj*         TclpNativeToNormalized 
                            _ANSI_ARGS_((ClientData clientData));
EXTERN Tcl_Obj*	        TclpFilesystemPathType
					_ANSI_ARGS_((Tcl_Obj* pathPtr));
EXTERN Tcl_PackageInitProc* TclpFindSymbol _ANSI_ARGS_((Tcl_Interp *interp,
			    Tcl_LoadHandle loadHandle, CONST char *symbol));
EXTERN int              TclpDlopen _ANSI_ARGS_((Tcl_Interp *interp, 
			    Tcl_Obj *pathPtr, 
	                    Tcl_LoadHandle *loadHandle, 
		            Tcl_FSUnloadFileProc **unloadProcPtr));
EXTERN int              TclpUtime _ANSI_ARGS_((Tcl_Obj *pathPtr,
1981
1982
1983
1984
1985
1986
1987


1988
1989
1990
1991
1992
1993
1994
EXTERN int	Tcl_InfoObjCmd _ANSI_ARGS_((ClientData clientData,
		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
EXTERN int	Tcl_InterpObjCmd _ANSI_ARGS_((ClientData clientData,
		    Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[]));
EXTERN int	Tcl_JoinObjCmd _ANSI_ARGS_((ClientData clientData,
		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
EXTERN int	Tcl_LappendObjCmd _ANSI_ARGS_((ClientData clientData,


		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
EXTERN int	Tcl_LindexObjCmd _ANSI_ARGS_((ClientData clientData,
		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
EXTERN int	Tcl_LinsertObjCmd _ANSI_ARGS_((ClientData clientData,
		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
EXTERN int	Tcl_LlengthObjCmd _ANSI_ARGS_((ClientData clientData,
		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));







>
>







2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
EXTERN int	Tcl_InfoObjCmd _ANSI_ARGS_((ClientData clientData,
		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
EXTERN int	Tcl_InterpObjCmd _ANSI_ARGS_((ClientData clientData,
		    Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[]));
EXTERN int	Tcl_JoinObjCmd _ANSI_ARGS_((ClientData clientData,
		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
EXTERN int	Tcl_LappendObjCmd _ANSI_ARGS_((ClientData clientData,
		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
EXTERN int	Tcl_LassignObjCmd _ANSI_ARGS_((ClientData clientData,
		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
EXTERN int	Tcl_LindexObjCmd _ANSI_ARGS_((ClientData clientData,
		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
EXTERN int	Tcl_LinsertObjCmd _ANSI_ARGS_((ClientData clientData,
		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
EXTERN int	Tcl_LlengthObjCmd _ANSI_ARGS_((ClientData clientData,
		    Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
2110
2111
2112
2113
2114
2115
2116


2117
2118
2119
2120
2121
2122
2123
		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
EXTERN int	TclCompileIfCmd _ANSI_ARGS_((Tcl_Interp *interp,
		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
EXTERN int	TclCompileIncrCmd _ANSI_ARGS_((Tcl_Interp *interp,
		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
EXTERN int	TclCompileLappendCmd _ANSI_ARGS_((Tcl_Interp *interp,
		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));


EXTERN int	TclCompileLindexCmd _ANSI_ARGS_((Tcl_Interp *interp,
		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
EXTERN int	TclCompileListCmd _ANSI_ARGS_((Tcl_Interp *interp,
		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
EXTERN int	TclCompileLlengthCmd _ANSI_ARGS_((Tcl_Interp *interp,
		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
EXTERN int	TclCompileLsetCmd _ANSI_ARGS_((Tcl_Interp* interp,







>
>







2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
EXTERN int	TclCompileIfCmd _ANSI_ARGS_((Tcl_Interp *interp,
		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
EXTERN int	TclCompileIncrCmd _ANSI_ARGS_((Tcl_Interp *interp,
		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
EXTERN int	TclCompileLappendCmd _ANSI_ARGS_((Tcl_Interp *interp,
		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
EXTERN int	TclCompileLassignCmd _ANSI_ARGS_((Tcl_Interp *interp,
		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
EXTERN int	TclCompileLindexCmd _ANSI_ARGS_((Tcl_Interp *interp,
		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
EXTERN int	TclCompileListCmd _ANSI_ARGS_((Tcl_Interp *interp,
		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
EXTERN int	TclCompileLlengthCmd _ANSI_ARGS_((Tcl_Interp *interp,
		    Tcl_Parse *parsePtr, struct CompileEnv *envPtr));
EXTERN int	TclCompileLsetCmd _ANSI_ARGS_((Tcl_Interp* interp,
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

# define TclNewObj(objPtr) \
    TclDbNewObj(objPtr, __FILE__, __LINE__);

# define TclDecrRefCount(objPtr) \
    Tcl_DbDecrRefCount(objPtr, __FILE__, __LINE__)




#elif defined(PURIFY)

/*
 * The PURIFY mode is like the regular mode, but instead of doing block
 * Tcl_Obj allocation and keeping a freed list for efficiency, it always
 * allocates and frees a single Tcl_Obj so that tools like Purify can
 * better track memory leaks
 */

#  define TclAllocObjStorage(objPtr) \
       (objPtr) = (Tcl_Obj *) Tcl_Ckalloc(sizeof(Tcl_Obj))

#  define TclFreeObjStorage(objPtr) \
       ckfree((char *) (objPtr))

#elif defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)

/*







>
>
>










|







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

# define TclNewObj(objPtr) \
    TclDbNewObj(objPtr, __FILE__, __LINE__);

# define TclDecrRefCount(objPtr) \
    Tcl_DbDecrRefCount(objPtr, __FILE__, __LINE__)

# define TclNewListObjDirect(objc, objv) \
    TclDbNewListObjDirect(objc, objv, __FILE__, __LINE__)

#elif defined(PURIFY)

/*
 * The PURIFY mode is like the regular mode, but instead of doing block
 * Tcl_Obj allocation and keeping a freed list for efficiency, it always
 * allocates and frees a single Tcl_Obj so that tools like Purify can
 * better track memory leaks
 */

#  define TclAllocObjStorage(objPtr) \
       (objPtr) = (Tcl_Obj *) Tcl_Alloc(sizeof(Tcl_Obj))

#  define TclFreeObjStorage(objPtr) \
       ckfree((char *) (objPtr))

#elif defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)

/*
Changes to generic/tclIntDecls.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * tclIntDecls.h --
 *
 *	This file contains the declarations for all unsupported
 *	functions that are exported by the Tcl library.  These
 *	interfaces are not guaranteed to remain the same between
 *	versions.  Use at your own risk.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclIntDecls.h,v 1.50.2.4 2003/09/05 23:10:05 dgp Exp $
 */

#ifndef _TCLINTDECLS
#define _TCLINTDECLS

/*
 * WARNING: This file is automatically generated by the tools/genStubs.tcl













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * tclIntDecls.h --
 *
 *	This file contains the declarations for all unsupported
 *	functions that are exported by the Tcl library.  These
 *	interfaces are not guaranteed to remain the same between
 *	versions.  Use at your own risk.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclIntDecls.h,v 1.50.2.5 2004/02/07 05:48:01 dgp Exp $
 */

#ifndef _TCLINTDECLS
#define _TCLINTDECLS

/*
 * WARNING: This file is automatically generated by the tools/genStubs.tcl
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#endif
#ifndef TclDeleteVars_TCL_DECLARED
#define TclDeleteVars_TCL_DECLARED
/* 12 */
EXTERN void		TclDeleteVars _ANSI_ARGS_((Interp * iPtr, 
				Tcl_HashTable * tablePtr));
#endif
#ifndef TclDoGlob_TCL_DECLARED
#define TclDoGlob_TCL_DECLARED
/* 13 */
EXTERN int		TclDoGlob _ANSI_ARGS_((Tcl_Interp * interp, 
				char * separators, Tcl_DString * headPtr, 
				char * tail, Tcl_GlobTypeData * types));
#endif
#ifndef TclDumpMemoryInfo_TCL_DECLARED
#define TclDumpMemoryInfo_TCL_DECLARED
/* 14 */
EXTERN void		TclDumpMemoryInfo _ANSI_ARGS_((FILE * outFile));
#endif
/* Slot 15 is reserved */
#ifndef TclExprFloatError_TCL_DECLARED







<
<
|
<
<
<
<







120
121
122
123
124
125
126


127




128
129
130
131
132
133
134
#endif
#ifndef TclDeleteVars_TCL_DECLARED
#define TclDeleteVars_TCL_DECLARED
/* 12 */
EXTERN void		TclDeleteVars _ANSI_ARGS_((Interp * iPtr, 
				Tcl_HashTable * tablePtr));
#endif


/* Slot 13 is reserved */




#ifndef TclDumpMemoryInfo_TCL_DECLARED
#define TclDumpMemoryInfo_TCL_DECLARED
/* 14 */
EXTERN void		TclDumpMemoryInfo _ANSI_ARGS_((FILE * outFile));
#endif
/* Slot 15 is reserved */
#ifndef TclExprFloatError_TCL_DECLARED
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
EXTERN Tcl_Channel	TclpGetDefaultStdChannel _ANSI_ARGS_((int type));
#endif
/* Slot 29 is reserved */
/* Slot 30 is reserved */
#ifndef TclGetExtension_TCL_DECLARED
#define TclGetExtension_TCL_DECLARED
/* 31 */
EXTERN char *		TclGetExtension _ANSI_ARGS_((char * name));
#endif
#ifndef TclGetFrame_TCL_DECLARED
#define TclGetFrame_TCL_DECLARED
/* 32 */
EXTERN int		TclGetFrame _ANSI_ARGS_((Tcl_Interp * interp, 
				CONST char * str, CallFrame ** framePtrPtr));
#endif







|







180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
EXTERN Tcl_Channel	TclpGetDefaultStdChannel _ANSI_ARGS_((int type));
#endif
/* Slot 29 is reserved */
/* Slot 30 is reserved */
#ifndef TclGetExtension_TCL_DECLARED
#define TclGetExtension_TCL_DECLARED
/* 31 */
EXTERN CONST char *	TclGetExtension _ANSI_ARGS_((CONST char * name));
#endif
#ifndef TclGetFrame_TCL_DECLARED
#define TclGetFrame_TCL_DECLARED
/* 32 */
EXTERN int		TclGetFrame _ANSI_ARGS_((Tcl_Interp * interp, 
				CONST char * str, CallFrame ** framePtrPtr));
#endif
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
#ifndef TclpStrftime_TCL_DECLARED
#define TclpStrftime_TCL_DECLARED
/* 134 */
EXTERN size_t		TclpStrftime _ANSI_ARGS_((char * s, size_t maxsize, 
				CONST char * format, CONST struct tm * t, 
				int useGMT));
#endif
#ifndef TclpCheckStackSpace_TCL_DECLARED
#define TclpCheckStackSpace_TCL_DECLARED
/* 135 */
EXTERN int		TclpCheckStackSpace _ANSI_ARGS_((void));
#endif
/* Slot 136 is reserved */
/* Slot 137 is reserved */
#ifndef TclGetEnv_TCL_DECLARED
#define TclGetEnv_TCL_DECLARED
/* 138 */
EXTERN CONST84_RETURN char * TclGetEnv _ANSI_ARGS_((CONST char * name, 
				Tcl_DString * valuePtr));







<
<
|
<
<







696
697
698
699
700
701
702


703


704
705
706
707
708
709
710
#ifndef TclpStrftime_TCL_DECLARED
#define TclpStrftime_TCL_DECLARED
/* 134 */
EXTERN size_t		TclpStrftime _ANSI_ARGS_((char * s, size_t maxsize, 
				CONST char * format, CONST struct tm * t, 
				int useGMT));
#endif


/* Slot 135 is reserved */


/* Slot 136 is reserved */
/* Slot 137 is reserved */
#ifndef TclGetEnv_TCL_DECLARED
#define TclGetEnv_TCL_DECLARED
/* 138 */
EXTERN CONST84_RETURN char * TclGetEnv _ANSI_ARGS_((CONST char * name, 
				Tcl_DString * valuePtr));
945
946
947
948
949
950
951












952
953
954
955
956
957
958
#endif
#ifndef Tcl_GetStartupScript_TCL_DECLARED
#define Tcl_GetStartupScript_TCL_DECLARED
/* 179 */
EXTERN Tcl_Obj *	Tcl_GetStartupScript _ANSI_ARGS_((
				CONST char ** encodingNamePtr));
#endif













typedef struct TclIntStubs {
    int magic;
    struct TclIntStubHooks *hooks;

    void *reserved0;
    int (*tclAccessDeleteProc) _ANSI_ARGS_((TclAccessProc_ * proc)); /* 1 */







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







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
#endif
#ifndef Tcl_GetStartupScript_TCL_DECLARED
#define Tcl_GetStartupScript_TCL_DECLARED
/* 179 */
EXTERN Tcl_Obj *	Tcl_GetStartupScript _ANSI_ARGS_((
				CONST char ** encodingNamePtr));
#endif
#ifndef TclNewListObjDirect_TCL_DECLARED
#define TclNewListObjDirect_TCL_DECLARED
/* 180 */
EXTERN Tcl_Obj *	TclNewListObjDirect _ANSI_ARGS_((int objc, 
				Tcl_Obj ** objv));
#endif
#ifndef TclDbNewListObjDirect_TCL_DECLARED
#define TclDbNewListObjDirect_TCL_DECLARED
/* 181 */
EXTERN Tcl_Obj *	TclDbNewListObjDirect _ANSI_ARGS_((int objc, 
				Tcl_Obj ** objv, CONST char * file, int line));
#endif

typedef struct TclIntStubs {
    int magic;
    struct TclIntStubHooks *hooks;

    void *reserved0;
    int (*tclAccessDeleteProc) _ANSI_ARGS_((TclAccessProc_ * proc)); /* 1 */
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
#endif /* __WIN32__ */
#ifdef MAC_TCL
    void *reserved9;
#endif /* MAC_TCL */
    int (*tclCreateProc) _ANSI_ARGS_((Tcl_Interp * interp, Namespace * nsPtr, CONST char * procName, Tcl_Obj * argsPtr, Tcl_Obj * bodyPtr, Proc ** procPtrPtr)); /* 10 */
    void (*tclDeleteCompiledLocalVars) _ANSI_ARGS_((Interp * iPtr, CallFrame * framePtr)); /* 11 */
    void (*tclDeleteVars) _ANSI_ARGS_((Interp * iPtr, Tcl_HashTable * tablePtr)); /* 12 */
    int (*tclDoGlob) _ANSI_ARGS_((Tcl_Interp * interp, char * separators, Tcl_DString * headPtr, char * tail, Tcl_GlobTypeData * types)); /* 13 */
    void (*tclDumpMemoryInfo) _ANSI_ARGS_((FILE * outFile)); /* 14 */
    void *reserved15;
    void (*tclExprFloatError) _ANSI_ARGS_((Tcl_Interp * interp, double value)); /* 16 */
    void *reserved17;
    void *reserved18;
    void *reserved19;
    void *reserved20;
    void *reserved21;
    int (*tclFindElement) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * listStr, int listLength, CONST char ** elementPtr, CONST char ** nextPtr, int * sizePtr, int * bracePtr)); /* 22 */
    Proc * (*tclFindProc) _ANSI_ARGS_((Interp * iPtr, CONST char * procName)); /* 23 */
    int (*tclFormatInt) _ANSI_ARGS_((char * buffer, long n)); /* 24 */
    void (*tclFreePackageInfo) _ANSI_ARGS_((Interp * iPtr)); /* 25 */
    void *reserved26;
    int (*tclGetDate) _ANSI_ARGS_((char * p, unsigned long now, long zone, unsigned long * timePtr)); /* 27 */
    Tcl_Channel (*tclpGetDefaultStdChannel) _ANSI_ARGS_((int type)); /* 28 */
    void *reserved29;
    void *reserved30;
    char * (*tclGetExtension) _ANSI_ARGS_((char * name)); /* 31 */
    int (*tclGetFrame) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * str, CallFrame ** framePtrPtr)); /* 32 */
    TclCmdProcType (*tclGetInterpProc) _ANSI_ARGS_((void)); /* 33 */
    int (*tclGetIntForIndex) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * objPtr, int endValue, int * indexPtr)); /* 34 */
    void *reserved35;
    int (*tclGetLong) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * str, long * longPtr)); /* 36 */
    int (*tclGetLoadedPackages) _ANSI_ARGS_((Tcl_Interp * interp, char * targetName)); /* 37 */
    int (*tclGetNamespaceForQualName) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * qualName, Namespace * cxtNsPtr, int flags, Namespace ** nsPtrPtr, Namespace ** altNsPtrPtr, Namespace ** actualCxtPtrPtr, CONST char ** simpleNamePtr)); /* 38 */







|

















|







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
#endif /* __WIN32__ */
#ifdef MAC_TCL
    void *reserved9;
#endif /* MAC_TCL */
    int (*tclCreateProc) _ANSI_ARGS_((Tcl_Interp * interp, Namespace * nsPtr, CONST char * procName, Tcl_Obj * argsPtr, Tcl_Obj * bodyPtr, Proc ** procPtrPtr)); /* 10 */
    void (*tclDeleteCompiledLocalVars) _ANSI_ARGS_((Interp * iPtr, CallFrame * framePtr)); /* 11 */
    void (*tclDeleteVars) _ANSI_ARGS_((Interp * iPtr, Tcl_HashTable * tablePtr)); /* 12 */
    void *reserved13;
    void (*tclDumpMemoryInfo) _ANSI_ARGS_((FILE * outFile)); /* 14 */
    void *reserved15;
    void (*tclExprFloatError) _ANSI_ARGS_((Tcl_Interp * interp, double value)); /* 16 */
    void *reserved17;
    void *reserved18;
    void *reserved19;
    void *reserved20;
    void *reserved21;
    int (*tclFindElement) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * listStr, int listLength, CONST char ** elementPtr, CONST char ** nextPtr, int * sizePtr, int * bracePtr)); /* 22 */
    Proc * (*tclFindProc) _ANSI_ARGS_((Interp * iPtr, CONST char * procName)); /* 23 */
    int (*tclFormatInt) _ANSI_ARGS_((char * buffer, long n)); /* 24 */
    void (*tclFreePackageInfo) _ANSI_ARGS_((Interp * iPtr)); /* 25 */
    void *reserved26;
    int (*tclGetDate) _ANSI_ARGS_((char * p, unsigned long now, long zone, unsigned long * timePtr)); /* 27 */
    Tcl_Channel (*tclpGetDefaultStdChannel) _ANSI_ARGS_((int type)); /* 28 */
    void *reserved29;
    void *reserved30;
    CONST char * (*tclGetExtension) _ANSI_ARGS_((CONST char * name)); /* 31 */
    int (*tclGetFrame) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * str, CallFrame ** framePtrPtr)); /* 32 */
    TclCmdProcType (*tclGetInterpProc) _ANSI_ARGS_((void)); /* 33 */
    int (*tclGetIntForIndex) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * objPtr, int endValue, int * indexPtr)); /* 34 */
    void *reserved35;
    int (*tclGetLong) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * str, long * longPtr)); /* 36 */
    int (*tclGetLoadedPackages) _ANSI_ARGS_((Tcl_Interp * interp, char * targetName)); /* 37 */
    int (*tclGetNamespaceForQualName) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * qualName, Namespace * cxtNsPtr, int flags, Namespace ** nsPtrPtr, Namespace ** altNsPtrPtr, Namespace ** actualCxtPtrPtr, CONST char ** simpleNamePtr)); /* 38 */
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
    void (*tcl_PopCallFrame) _ANSI_ARGS_((Tcl_Interp * interp)); /* 128 */
    int (*tcl_PushCallFrame) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_CallFrame * framePtr, Tcl_Namespace * nsPtr, int isProcCallFrame)); /* 129 */
    int (*tcl_RemoveInterpResolvers) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * name)); /* 130 */
    void (*tcl_SetNamespaceResolvers) _ANSI_ARGS_((Tcl_Namespace * namespacePtr, Tcl_ResolveCmdProc * cmdProc, Tcl_ResolveVarProc * varProc, Tcl_ResolveCompiledVarProc * compiledVarProc)); /* 131 */
    int (*tclpHasSockets) _ANSI_ARGS_((Tcl_Interp * interp)); /* 132 */
    struct tm * (*tclpGetDate) _ANSI_ARGS_((TclpTime_t time, int useGMT)); /* 133 */
    size_t (*tclpStrftime) _ANSI_ARGS_((char * s, size_t maxsize, CONST char * format, CONST struct tm * t, int useGMT)); /* 134 */
    int (*tclpCheckStackSpace) _ANSI_ARGS_((void)); /* 135 */
    void *reserved136;
    void *reserved137;
    CONST84_RETURN char * (*tclGetEnv) _ANSI_ARGS_((CONST char * name, Tcl_DString * valuePtr)); /* 138 */
    void *reserved139;
    int (*tclLooksLikeInt) _ANSI_ARGS_((CONST char * bytes, int length)); /* 140 */
    CONST84_RETURN char * (*tclpGetCwd) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_DString * cwdPtr)); /* 141 */
    int (*tclSetByteCodeFromAny) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * objPtr, CompileHookProc * hookProc, ClientData clientData)); /* 142 */







|







1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
    void (*tcl_PopCallFrame) _ANSI_ARGS_((Tcl_Interp * interp)); /* 128 */
    int (*tcl_PushCallFrame) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_CallFrame * framePtr, Tcl_Namespace * nsPtr, int isProcCallFrame)); /* 129 */
    int (*tcl_RemoveInterpResolvers) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * name)); /* 130 */
    void (*tcl_SetNamespaceResolvers) _ANSI_ARGS_((Tcl_Namespace * namespacePtr, Tcl_ResolveCmdProc * cmdProc, Tcl_ResolveVarProc * varProc, Tcl_ResolveCompiledVarProc * compiledVarProc)); /* 131 */
    int (*tclpHasSockets) _ANSI_ARGS_((Tcl_Interp * interp)); /* 132 */
    struct tm * (*tclpGetDate) _ANSI_ARGS_((TclpTime_t time, int useGMT)); /* 133 */
    size_t (*tclpStrftime) _ANSI_ARGS_((char * s, size_t maxsize, CONST char * format, CONST struct tm * t, int useGMT)); /* 134 */
    void *reserved135;
    void *reserved136;
    void *reserved137;
    CONST84_RETURN char * (*tclGetEnv) _ANSI_ARGS_((CONST char * name, Tcl_DString * valuePtr)); /* 138 */
    void *reserved139;
    int (*tclLooksLikeInt) _ANSI_ARGS_((CONST char * bytes, int length)); /* 140 */
    CONST84_RETURN char * (*tclpGetCwd) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_DString * cwdPtr)); /* 141 */
    int (*tclSetByteCodeFromAny) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * objPtr, CompileHookProc * hookProc, ClientData clientData)); /* 142 */
1154
1155
1156
1157
1158
1159
1160


1161
1162
1163
1164
1165
1166
1167
    int (*tclUniCharMatch) _ANSI_ARGS_((CONST Tcl_UniChar * string, int strLen, CONST Tcl_UniChar * pattern, int ptnLen, int nocase)); /* 173 */
    Tcl_Obj * (*tclIncrWideVar2) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * part1Ptr, Tcl_Obj * part2Ptr, Tcl_WideInt wideIncrAmount, int part1NotParsed)); /* 174 */
    int (*tclCallVarTraces) _ANSI_ARGS_((Interp * iPtr, Var * arrayPtr, Var * varPtr, CONST char * part1, CONST char * part2, int flags, int leaveErrMsg)); /* 175 */
    void (*tclCleanupVar) _ANSI_ARGS_((Var * varPtr, Var * arrayPtr)); /* 176 */
    void (*tclVarErrMsg) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * part1, CONST char * part2, CONST char * operation, CONST char * reason)); /* 177 */
    void (*tcl_SetStartupScript) _ANSI_ARGS_((Tcl_Obj * pathPtr, CONST char* encodingName)); /* 178 */
    Tcl_Obj * (*tcl_GetStartupScript) _ANSI_ARGS_((CONST char ** encodingNamePtr)); /* 179 */


} TclIntStubs;

#ifdef __cplusplus
extern "C" {
#endif
extern TclIntStubs *tclIntStubsPtr;
#ifdef __cplusplus







>
>







1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
    int (*tclUniCharMatch) _ANSI_ARGS_((CONST Tcl_UniChar * string, int strLen, CONST Tcl_UniChar * pattern, int ptnLen, int nocase)); /* 173 */
    Tcl_Obj * (*tclIncrWideVar2) _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * part1Ptr, Tcl_Obj * part2Ptr, Tcl_WideInt wideIncrAmount, int part1NotParsed)); /* 174 */
    int (*tclCallVarTraces) _ANSI_ARGS_((Interp * iPtr, Var * arrayPtr, Var * varPtr, CONST char * part1, CONST char * part2, int flags, int leaveErrMsg)); /* 175 */
    void (*tclCleanupVar) _ANSI_ARGS_((Var * varPtr, Var * arrayPtr)); /* 176 */
    void (*tclVarErrMsg) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * part1, CONST char * part2, CONST char * operation, CONST char * reason)); /* 177 */
    void (*tcl_SetStartupScript) _ANSI_ARGS_((Tcl_Obj * pathPtr, CONST char* encodingName)); /* 178 */
    Tcl_Obj * (*tcl_GetStartupScript) _ANSI_ARGS_((CONST char ** encodingNamePtr)); /* 179 */
    Tcl_Obj * (*tclNewListObjDirect) _ANSI_ARGS_((int objc, Tcl_Obj ** objv)); /* 180 */
    Tcl_Obj * (*tclDbNewListObjDirect) _ANSI_ARGS_((int objc, Tcl_Obj ** objv, CONST char * file, int line)); /* 181 */
} TclIntStubs;

#ifdef __cplusplus
extern "C" {
#endif
extern TclIntStubs *tclIntStubsPtr;
#ifdef __cplusplus
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
#define TclDeleteCompiledLocalVars \
	(tclIntStubsPtr->tclDeleteCompiledLocalVars) /* 11 */
#endif
#ifndef TclDeleteVars
#define TclDeleteVars \
	(tclIntStubsPtr->tclDeleteVars) /* 12 */
#endif
#ifndef TclDoGlob
#define TclDoGlob \
	(tclIntStubsPtr->tclDoGlob) /* 13 */
#endif
#ifndef TclDumpMemoryInfo
#define TclDumpMemoryInfo \
	(tclIntStubsPtr->tclDumpMemoryInfo) /* 14 */
#endif
/* Slot 15 is reserved */
#ifndef TclExprFloatError
#define TclExprFloatError \







|
<
<
<







1236
1237
1238
1239
1240
1241
1242
1243



1244
1245
1246
1247
1248
1249
1250
#define TclDeleteCompiledLocalVars \
	(tclIntStubsPtr->tclDeleteCompiledLocalVars) /* 11 */
#endif
#ifndef TclDeleteVars
#define TclDeleteVars \
	(tclIntStubsPtr->tclDeleteVars) /* 12 */
#endif
/* Slot 13 is reserved */



#ifndef TclDumpMemoryInfo
#define TclDumpMemoryInfo \
	(tclIntStubsPtr->tclDumpMemoryInfo) /* 14 */
#endif
/* Slot 15 is reserved */
#ifndef TclExprFloatError
#define TclExprFloatError \
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
#define TclpGetDate \
	(tclIntStubsPtr->tclpGetDate) /* 133 */
#endif
#ifndef TclpStrftime
#define TclpStrftime \
	(tclIntStubsPtr->tclpStrftime) /* 134 */
#endif
#ifndef TclpCheckStackSpace
#define TclpCheckStackSpace \
	(tclIntStubsPtr->tclpCheckStackSpace) /* 135 */
#endif
/* Slot 136 is reserved */
/* Slot 137 is reserved */
#ifndef TclGetEnv
#define TclGetEnv \
	(tclIntStubsPtr->tclGetEnv) /* 138 */
#endif
/* Slot 139 is reserved */







<
<
|
<







1627
1628
1629
1630
1631
1632
1633


1634

1635
1636
1637
1638
1639
1640
1641
#define TclpGetDate \
	(tclIntStubsPtr->tclpGetDate) /* 133 */
#endif
#ifndef TclpStrftime
#define TclpStrftime \
	(tclIntStubsPtr->tclpStrftime) /* 134 */
#endif


/* Slot 135 is reserved */

/* Slot 136 is reserved */
/* Slot 137 is reserved */
#ifndef TclGetEnv
#define TclGetEnv \
	(tclIntStubsPtr->tclGetEnv) /* 138 */
#endif
/* Slot 139 is reserved */
1788
1789
1790
1791
1792
1793
1794








1795
1796
1797
1798
1799
1800
#define Tcl_SetStartupScript \
	(tclIntStubsPtr->tcl_SetStartupScript) /* 178 */
#endif
#ifndef Tcl_GetStartupScript
#define Tcl_GetStartupScript \
	(tclIntStubsPtr->tcl_GetStartupScript) /* 179 */
#endif









#endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */

/* !END!: Do not edit above this line. */

#endif /* _TCLINTDECLS */







>
>
>
>
>
>
>
>






1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
#define Tcl_SetStartupScript \
	(tclIntStubsPtr->tcl_SetStartupScript) /* 178 */
#endif
#ifndef Tcl_GetStartupScript
#define Tcl_GetStartupScript \
	(tclIntStubsPtr->tcl_GetStartupScript) /* 179 */
#endif
#ifndef TclNewListObjDirect
#define TclNewListObjDirect \
	(tclIntStubsPtr->tclNewListObjDirect) /* 180 */
#endif
#ifndef TclDbNewListObjDirect
#define TclDbNewListObjDirect \
	(tclIntStubsPtr->tclDbNewListObjDirect) /* 181 */
#endif

#endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */

/* !END!: Do not edit above this line. */

#endif /* _TCLINTDECLS */
Changes to generic/tclInterp.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclInterp.c --
 *
 *	This file implements the "interp" command which allows creation
 *	and manipulation of Tcl interpreters from within Tcl scripts.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclInterp.c,v 1.22.2.1 2003/10/16 02:28:02 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include <stdio.h>

/*











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclInterp.c --
 *
 *	This file implements the "interp" command which allows creation
 *	and manipulation of Tcl interpreters from within Tcl scripts.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclInterp.c,v 1.22.2.2 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include <stdio.h>

/*
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295

    /*
     * There shouldn't be any commands left.
     */

    masterPtr = &interpInfoPtr->master;
    if (masterPtr->slaveTable.numEntries != 0) {
	panic("InterpInfoDeleteProc: still exist commands");
    }
    Tcl_DeleteHashTable(&masterPtr->slaveTable);

    /*
     * Tell any interps that have aliases to this interp that they should
     * delete those aliases.  If the other interp was already dead, it
     * would have removed the target record already. 







|







281
282
283
284
285
286
287
288
289
290
291
292
293
294
295

    /*
     * There shouldn't be any commands left.
     */

    masterPtr = &interpInfoPtr->master;
    if (masterPtr->slaveTable.numEntries != 0) {
	Tcl_Panic("InterpInfoDeleteProc: still exist commands");
    }
    Tcl_DeleteHashTable(&masterPtr->slaveTable);

    /*
     * Tell any interps that have aliases to this interp that they should
     * delete those aliases.  If the other interp was already dead, it
     * would have removed the target record already. 
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
    }

    /*
     * There shouldn't be any aliases left.
     */

    if (slavePtr->aliasTable.numEntries != 0) {
	panic("InterpInfoDeleteProc: still exist aliases");
    }
    Tcl_DeleteHashTable(&slavePtr->aliasTable);

    ckfree((char *) interpInfoPtr);    
}

/*







|







319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
    }

    /*
     * There shouldn't be any aliases left.
     */

    if (slavePtr->aliasTable.numEntries != 0) {
	Tcl_Panic("InterpInfoDeleteProc: still exist aliases");
    }
    Tcl_DeleteHashTable(&slavePtr->aliasTable);

    ckfree((char *) interpInfoPtr);    
}

/*
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
	OPT_ALIAS,	OPT_ALIASES,	OPT_EVAL,	OPT_EXPOSE,
	OPT_HIDE,	OPT_HIDDEN,	OPT_ISSAFE,	OPT_INVOKEHIDDEN,
	OPT_MARKTRUSTED, OPT_RECLIMIT
    };
    
    slaveInterp = (Tcl_Interp *) clientData;
    if (slaveInterp == NULL) {
	panic("SlaveObjCmd: interpreter has been deleted");
    }

    if (objc < 2) {
        Tcl_WrongNumArgs(interp, 1, objv, "cmd ?arg ...?");
        return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0,







|







1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
	OPT_ALIAS,	OPT_ALIASES,	OPT_EVAL,	OPT_EXPOSE,
	OPT_HIDE,	OPT_HIDDEN,	OPT_ISSAFE,	OPT_INVOKEHIDDEN,
	OPT_MARKTRUSTED, OPT_RECLIMIT
    };
    
    slaveInterp = (Tcl_Interp *) clientData;
    if (slaveInterp == NULL) {
	Tcl_Panic("SlaveObjCmd: interpreter has been deleted");
    }

    if (objc < 2) {
        Tcl_WrongNumArgs(interp, 1, objv, "cmd ?arg ...?");
        return TCL_ERROR;
    }
    if (Tcl_GetIndexFromObj(interp, objv[1], options, "option", 0,
Changes to generic/tclListObj.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclListObj.c --
 *
 *	This file contains procedures that implement the Tcl list object
 *	type.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998 by Scriptics Corporation.
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclListObj.c,v 1.13.6.1 2003/09/05 23:08:07 dgp Exp $
 */

#include "tclInt.h"

/*
 * Prototypes for procedures defined later in this file:
 */













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclListObj.c --
 *
 *	This file contains procedures that implement the Tcl list object
 *	type.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998 by Scriptics Corporation.
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclListObj.c,v 1.13.6.2 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"

/*
 * Prototypes for procedures defined later in this file:
 */
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
 * it is occasionally used as working storage to avoid an auxiliary
 * stack.
 */

Tcl_ObjType tclListType = {
    "list",				/* name */
    FreeListInternalRep,		/* freeIntRepProc */
    DupListInternalRep,		        /* dupIntRepProc */
    UpdateStringOfList,			/* updateStringProc */
    SetListFromAny			/* setFromAnyProc */
};

/*
 *----------------------------------------------------------------------
 *







|







40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
 * it is occasionally used as working storage to avoid an auxiliary
 * stack.
 */

Tcl_ObjType tclListType = {
    "list",				/* name */
    FreeListInternalRep,		/* freeIntRepProc */
    DupListInternalRep,			/* dupIntRepProc */
    UpdateStringOfList,			/* updateStringProc */
    SetListFromAny			/* setFromAnyProc */
};

/*
 *----------------------------------------------------------------------
 *
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
    int objc;			/* Count of objects referenced by objv. */
    Tcl_Obj *CONST objv[];	/* An array of pointers to Tcl objects. */
{
    register Tcl_Obj *listPtr;
    register Tcl_Obj **elemPtrs;
    register List *listRepPtr;
    int i;
    
    TclNewObj(listPtr);
    
    if (objc > 0) {
	Tcl_InvalidateStringRep(listPtr);
	
	elemPtrs = (Tcl_Obj **)
	    ckalloc((unsigned) (objc * sizeof(Tcl_Obj *)));
	for (i = 0;  i < objc;  i++) {
	    elemPtrs[i] = objv[i];
	    Tcl_IncrRefCount(elemPtrs[i]);
	}
	
	listRepPtr = (List *) ckalloc(sizeof(List));
	listRepPtr->maxElemCount = objc;
	listRepPtr->elemCount    = objc;
	listRepPtr->elements     = elemPtrs;
	
	listPtr->internalRep.twoPtrValue.ptr1 = (VOID *) listRepPtr;
	listPtr->internalRep.twoPtrValue.ptr2 = NULL;
	listPtr->typePtr = &tclListType;
    }
    return listPtr;
}
#endif /* if TCL_MEM_DEBUG */







|

|


|






|




|







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
    int objc;			/* Count of objects referenced by objv. */
    Tcl_Obj *CONST objv[];	/* An array of pointers to Tcl objects. */
{
    register Tcl_Obj *listPtr;
    register Tcl_Obj **elemPtrs;
    register List *listRepPtr;
    int i;

    TclNewObj(listPtr);

    if (objc > 0) {
	Tcl_InvalidateStringRep(listPtr);

	elemPtrs = (Tcl_Obj **)
	    ckalloc((unsigned) (objc * sizeof(Tcl_Obj *)));
	for (i = 0;  i < objc;  i++) {
	    elemPtrs[i] = objv[i];
	    Tcl_IncrRefCount(elemPtrs[i]);
	}

	listRepPtr = (List *) ckalloc(sizeof(List));
	listRepPtr->maxElemCount = objc;
	listRepPtr->elemCount    = objc;
	listRepPtr->elements     = elemPtrs;

	listPtr->internalRep.twoPtrValue.ptr1 = (VOID *) listRepPtr;
	listPtr->internalRep.twoPtrValue.ptr2 = NULL;
	listPtr->typePtr = &tclListType;
    }
    return listPtr;
}
#endif /* if TCL_MEM_DEBUG */
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
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
    register Tcl_Obj *listPtr;
    register Tcl_Obj **elemPtrs;
    register List *listRepPtr;
    int i;
    
    TclDbNewObj(listPtr, file, line);
    
    if (objc > 0) {
	Tcl_InvalidateStringRep(listPtr);
	
	elemPtrs = (Tcl_Obj **)
	    ckalloc((unsigned) (objc * sizeof(Tcl_Obj *)));
	for (i = 0;  i < objc;  i++) {
	    elemPtrs[i] = objv[i];
	    Tcl_IncrRefCount(elemPtrs[i]);
	}
	
	listRepPtr = (List *) ckalloc(sizeof(List));
	listRepPtr->maxElemCount = objc;
	listRepPtr->elemCount    = objc;
	listRepPtr->elements     = elemPtrs;
	
	listPtr->internalRep.twoPtrValue.ptr1 = (VOID *) listRepPtr;
	listPtr->internalRep.twoPtrValue.ptr2 = NULL;
	listPtr->typePtr = &tclListType;
    }
    return listPtr;
}

#else /* if not TCL_MEM_DEBUG */

Tcl_Obj *
Tcl_DbNewListObj(objc, objv, file, line)
    int objc;			/* Count of objects referenced by objv. */
    Tcl_Obj *CONST objv[];	/* An array of pointers to Tcl objects. */
    CONST char *file;		/* The name of the source file calling this
				 * procedure; used for debugging. */
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
    return Tcl_NewListObj(objc, objv);
}


















































































































#endif /* TCL_MEM_DEBUG */

/*
 *----------------------------------------------------------------------
 *
 * Tcl_SetListObj --
 *







|

|


|






|




|




















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







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
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
    register Tcl_Obj *listPtr;
    register Tcl_Obj **elemPtrs;
    register List *listRepPtr;
    int i;

    TclDbNewObj(listPtr, file, line);

    if (objc > 0) {
	Tcl_InvalidateStringRep(listPtr);

	elemPtrs = (Tcl_Obj **)
	    ckalloc((unsigned) (objc * sizeof(Tcl_Obj *)));
	for (i = 0;  i < objc;  i++) {
	    elemPtrs[i] = objv[i];
	    Tcl_IncrRefCount(elemPtrs[i]);
	}

	listRepPtr = (List *) ckalloc(sizeof(List));
	listRepPtr->maxElemCount = objc;
	listRepPtr->elemCount    = objc;
	listRepPtr->elements     = elemPtrs;

	listPtr->internalRep.twoPtrValue.ptr1 = (VOID *) listRepPtr;
	listPtr->internalRep.twoPtrValue.ptr2 = NULL;
	listPtr->typePtr = &tclListType;
    }
    return listPtr;
}

#else /* if not TCL_MEM_DEBUG */

Tcl_Obj *
Tcl_DbNewListObj(objc, objv, file, line)
    int objc;			/* Count of objects referenced by objv. */
    Tcl_Obj *CONST objv[];	/* An array of pointers to Tcl objects. */
    CONST char *file;		/* The name of the source file calling this
				 * procedure; used for debugging. */
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
    return Tcl_NewListObj(objc, objv);
}
#endif /* TCL_MEM_DEBUG */

/*
 *----------------------------------------------------------------------
 *
 * TclNewListObjDirect, TclDbNewListObjDirect --
 *
 *	Version of Tcl_NewListOb/Tcl_DbNewListObj that does not copy
 *	the array of Tcl_Objs. It still scans it though to update the
 *	reference counts.
 *
 * Results:
 *	A new list object is returned that is initialized from the object
 *	pointers in objv. If objc is less than or equal to zero, an empty
 *	object is returned (and "ownership" of the array of objects is
 *	not transferred.) The new object's string representation is left
 *	NULL. The resulting new list object has ref count 0.
 *
 * Side effects:
 *	The ref counts of the elements in objv are incremented since the
 *	resulting list now refers to them.
 *
 *----------------------------------------------------------------------
 */

#ifdef TCL_MEM_DEBUG
#undef TclNewListObjDirect
Tcl_Obj *
TclNewListObjDirect(objc, objv)
    int objc;			/* Count of objects referenced by objv. */
    Tcl_Obj **objv;		/* An array of pointers to Tcl objects. */
{
    return TclDbNewListObjDirect(objc, objv, "unknown", 0);
}
#else /* !TCL_MEM_DEBUG */
Tcl_Obj *
TclNewListObjDirect(objc, objv)
    int objc;			/* Count of objects referenced by objv. */
    Tcl_Obj **objv;		/* An array of pointers to Tcl objects. */
{
    register Tcl_Obj *listPtr;

    TclNewObj(listPtr);

    if (objc > 0) {
	register List *listRepPtr;
	int i;

	Tcl_InvalidateStringRep(listPtr);

	for (i=0 ; i<objc ; i++) {
	    Tcl_IncrRefCount(objv[i]);
	}

	listRepPtr = (List *) ckalloc(sizeof(List));
	listRepPtr->maxElemCount = objc;
	listRepPtr->elemCount    = objc;
	listRepPtr->elements     = objv;

	listPtr->internalRep.twoPtrValue.ptr1 = (VOID *) listRepPtr;
	listPtr->internalRep.twoPtrValue.ptr2 = NULL;
	listPtr->typePtr = &tclListType;
    }
    return listPtr;
}
#endif /* TCL_MEM_DEBUG */

#ifdef TCL_MEM_DEBUG
Tcl_Obj *
TclDbNewListObjDirect(objc, objv, file, line)
    int objc;			/* Count of objects referenced by objv. */
    Tcl_Obj **objv;		/* An array of pointers to Tcl objects. */
    CONST char *file;		/* The name of the source file calling this
				 * procedure; used for debugging. */
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
    register Tcl_Obj *listPtr;

    TclDbNewObj(listPtr, file, line);

    if (objc > 0) {
	register List *listRepPtr;
	int i;

	Tcl_InvalidateStringRep(listPtr);

	for (i=0 ; i<objc ; i++) {
	    Tcl_IncrRefCount(objv[i]);
	}

	listRepPtr = (List *) ckalloc(sizeof(List));
	listRepPtr->maxElemCount = objc;
	listRepPtr->elemCount    = objc;
	listRepPtr->elements     = objv;

	listPtr->internalRep.twoPtrValue.ptr1 = (VOID *) listRepPtr;
	listPtr->internalRep.twoPtrValue.ptr2 = NULL;
	listPtr->typePtr = &tclListType;
    }
    return listPtr;
}
#else /* !TCL_MEM_DEBUG */
Tcl_Obj *
TclDbNewListObjDirect(objc, objv, file, line)
    int objc;			/* Count of objects referenced by objv. */
    Tcl_Obj **objv;		/* An array of pointers to Tcl objects. */
    CONST char *file;		/* The name of the source file calling this
				 * procedure; used for debugging. */
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
    return TclNewListObjDirect(objc, objv);
}
#endif /* TCL_MEM_DEBUG */

/*
 *----------------------------------------------------------------------
 *
 * Tcl_SetListObj --
 *
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
{
    register Tcl_Obj **elemPtrs;
    register List *listRepPtr;
    Tcl_ObjType *oldTypePtr = objPtr->typePtr;
    int i;

    if (Tcl_IsShared(objPtr)) {
	panic("Tcl_SetListObj called with shared object");
    }
    
    /*
     * Free any old string rep and any internal rep for the old type.
     */

    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(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) {
	elemPtrs = (Tcl_Obj **)
	    ckalloc((unsigned) (objc * sizeof(Tcl_Obj *)));
	for (i = 0;  i < objc;  i++) {
	    elemPtrs[i] = objv[i];
	    Tcl_IncrRefCount(elemPtrs[i]);
	}
	
	listRepPtr = (List *) ckalloc(sizeof(List));
	listRepPtr->maxElemCount = objc;
	listRepPtr->elemCount    = objc;
	listRepPtr->elements     = elemPtrs;
	
	objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) listRepPtr;
	objPtr->internalRep.twoPtrValue.ptr2 = NULL;
	objPtr->typePtr = &tclListType;
    } else {
	objPtr->bytes = tclEmptyStringRep;
	objPtr->length = 0;
    }







|

|









|













|




|







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
{
    register Tcl_Obj **elemPtrs;
    register List *listRepPtr;
    Tcl_ObjType *oldTypePtr = objPtr->typePtr;
    int i;

    if (Tcl_IsShared(objPtr)) {
	Tcl_Panic("Tcl_SetListObj called with shared object");
    }

    /*
     * Free any old string rep and any internal rep for the old type.
     */

    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(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) {
	elemPtrs = (Tcl_Obj **)
	    ckalloc((unsigned) (objc * sizeof(Tcl_Obj *)));
	for (i = 0;  i < objc;  i++) {
	    elemPtrs[i] = objv[i];
	    Tcl_IncrRefCount(elemPtrs[i]);
	}

	listRepPtr = (List *) ckalloc(sizeof(List));
	listRepPtr->maxElemCount = objc;
	listRepPtr->elemCount    = objc;
	listRepPtr->elements     = elemPtrs;

	objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) listRepPtr;
	objPtr->internalRep.twoPtrValue.ptr2 = NULL;
	objPtr->typePtr = &tclListType;
    } else {
	objPtr->bytes = tclEmptyStringRep;
	objPtr->length = 0;
    }
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
int
Tcl_ListObjGetElements(interp, listPtr, objcPtr, objvPtr)
    Tcl_Interp *interp;		/* Used to report errors if not NULL. */
    register Tcl_Obj *listPtr;	/* List object for which an element array
				 * is to be returned. */
    int *objcPtr;		/* Where to store the count of objects
				 * 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 = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {







|







429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
int
Tcl_ListObjGetElements(interp, listPtr, objcPtr, objvPtr)
    Tcl_Interp *interp;		/* Used to report errors if not NULL. */
    register Tcl_Obj *listPtr;	/* List object for which an element array
				 * is to be returned. */
    int *objcPtr;		/* Where to store the count of objects
				 * 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 = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
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
    Tcl_Obj *elemListPtr;	/* List obj with elements to append. */
{
    register List *listRepPtr;
    int listLen, objc, result;
    Tcl_Obj **objv;

    if (Tcl_IsShared(listPtr)) {
	panic("Tcl_ListObjAppendList called with shared object");
    }
    if (listPtr->typePtr != &tclListType) {
	result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }
    listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
    listLen = listRepPtr->elemCount;

    result = Tcl_ListObjGetElements(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 --







|



















|







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
    Tcl_Obj *elemListPtr;	/* List obj with elements to append. */
{
    register List *listRepPtr;
    int listLen, objc, result;
    Tcl_Obj **objv;

    if (Tcl_IsShared(listPtr)) {
	Tcl_Panic("Tcl_ListObjAppendList called with shared object");
    }
    if (listPtr->typePtr != &tclListType) {
	result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }
    listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
    listLen = listRepPtr->elemCount;

    result = Tcl_ListObjGetElements(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 --
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
    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;
    
    if (Tcl_IsShared(listPtr)) {
	panic("Tcl_ListObjAppendElement called with shared object");
    }
    if (listPtr->typePtr != &tclListType) {
	int result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }

    listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
    elemPtrs = listRepPtr->elements;
    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 (numRequired > listRepPtr->maxElemCount) {
	int newMax = (2 * numRequired);
	Tcl_Obj **newElemPtrs = (Tcl_Obj **)
	    ckalloc((unsigned) (newMax * sizeof(Tcl_Obj *)));
	
	memcpy((VOID *) newElemPtrs, (VOID *) elemPtrs,
	       (size_t) (numElems * sizeof(Tcl_Obj *)));

	listRepPtr->maxElemCount = newMax;
	listRepPtr->elements = newElemPtrs;
	ckfree((char *) elemPtrs);
	elemPtrs = newElemPtrs;
    }








|

|












|








|
|

|







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
    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;

    if (Tcl_IsShared(listPtr)) {
	Tcl_Panic("Tcl_ListObjAppendElement called with shared object");
    }
    if (listPtr->typePtr != &tclListType) {
	int result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }

    listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
    elemPtrs = listRepPtr->elements;
    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 (numRequired > listRepPtr->maxElemCount) {
	int newMax = (2 * numRequired);
	Tcl_Obj **newElemPtrs = (Tcl_Obj **)
		ckalloc((unsigned) (newMax * sizeof(Tcl_Obj *)));

	memcpy((VOID *) newElemPtrs, (VOID *) elemPtrs,
		(size_t) (numElems * sizeof(Tcl_Obj *)));

	listRepPtr->maxElemCount = newMax;
	listRepPtr->elements = newElemPtrs;
	ckfree((char *) elemPtrs);
	elemPtrs = newElemPtrs;
    }

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
Tcl_ListObjIndex(interp, listPtr, index, objPtrPtr)
    Tcl_Interp *interp;		/* Used to report errors if not NULL. */
    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 = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }

    listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
    if ((index < 0) || (index >= listRepPtr->elemCount)) {
	*objPtrPtr = NULL;
    } else {
	*objPtrPtr = listRepPtr->elements[index];
    }
    
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ListObjLength --







|













|







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
Tcl_ListObjIndex(interp, listPtr, index, objPtrPtr)
    Tcl_Interp *interp;		/* Used to report errors if not NULL. */
    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 = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }

    listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
    if ((index < 0) || (index >= listRepPtr->elemCount)) {
	*objPtrPtr = NULL;
    } else {
	*objPtrPtr = listRepPtr->elements[index];
    }

    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_ListObjLength --
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
int
Tcl_ListObjLength(interp, listPtr, intPtr)
    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 = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }








|







677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
int
Tcl_ListObjLength(interp, listPtr, intPtr)
    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 = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }

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
				 * to insert. */
{
    List *listRepPtr;
    register Tcl_Obj **elemPtrs, **newPtrs;
    Tcl_Obj *victimPtr;
    int numElems, numRequired, numAfterLast;
    int start, shift, newMax, i, j, result;
     
    if (Tcl_IsShared(listPtr)) {
	panic("Tcl_ListObjReplace called with shared object");
    }
    if (listPtr->typePtr != &tclListType) {
	result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }
    listRepPtr = (List *) 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;
    }
    
    numRequired = (numElems - count + objc);
    if (numRequired <= listRepPtr->maxElemCount) {
	/*
	 * Enough room in the current array. First "delete" count
	 * elements starting at first.
	 */








|

|




















|







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
				 * to insert. */
{
    List *listRepPtr;
    register Tcl_Obj **elemPtrs, **newPtrs;
    Tcl_Obj *victimPtr;
    int numElems, numRequired, numAfterLast;
    int start, shift, newMax, i, j, result;

    if (Tcl_IsShared(listPtr)) {
	Tcl_Panic("Tcl_ListObjReplace called with shared object");
    }
    if (listPtr->typePtr != &tclListType) {
	result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }
    listRepPtr = (List *) 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;
    }

    numRequired = (numElems - count + objc);
    if (numRequired <= listRepPtr->maxElemCount) {
	/*
	 * Enough room in the current array. First "delete" count
	 * elements starting at first.
	 */

693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
	    }
	}

	/*
	 * Insert the new elements into elemPtrs before "first".
	 */

	for (i = 0, j = first;  i < objc;  i++, j++) {
            elemPtrs[j] = objv[i];
            Tcl_IncrRefCount(objv[i]);
        }

	/*
	 * Update the count of elements.
	 */

	listRepPtr->elemCount = numRequired;
    } else {







|
|
|
|







807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
	    }
	}

	/*
	 * Insert the new elements into elemPtrs before "first".
	 */

	for (i=0,j=first ; i<objc ; i++,j++) {
	    elemPtrs[j] = objv[i];
	    Tcl_IncrRefCount(objv[i]);
	}

	/*
	 * Update the count of elements.
	 */

	listRepPtr->elemCount = numRequired;
    } else {
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
	start = (first + count);
	numAfterLast = (numElems - start);
	if (numAfterLast > 0) {
	    memcpy((VOID *) &(newPtrs[first + objc]),
		    (VOID *) &(elemPtrs[start]),
		    (size_t) (numAfterLast * sizeof(Tcl_Obj *)));
	}
	
	/*
	 * Insert the new elements before "first" and update the
	 * count of elements.
	 */

	for (i = 0, j = first;  i < objc;  i++, j++) {
	    newPtrs[j] = objv[i];
	    Tcl_IncrRefCount(objv[i]);
	}

	listRepPtr->elemCount = numRequired;
	listRepPtr->maxElemCount = newMax;
	listRepPtr->elements = newPtrs;
	ckfree((char *) elemPtrs);
    }
    
    /*
     * Invalidate and free any old string representation since it no longer
     * reflects the list's internal representation.
     */

    Tcl_InvalidateStringRep(listPtr);
    return TCL_OK;







|















|







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
	start = (first + count);
	numAfterLast = (numElems - start);
	if (numAfterLast > 0) {
	    memcpy((VOID *) &(newPtrs[first + objc]),
		    (VOID *) &(elemPtrs[start]),
		    (size_t) (numAfterLast * sizeof(Tcl_Obj *)));
	}

	/*
	 * Insert the new elements before "first" and update the
	 * count of elements.
	 */

	for (i = 0, j = first;  i < objc;  i++, j++) {
	    newPtrs[j] = objv[i];
	    Tcl_IncrRefCount(objv[i]);
	}

	listRepPtr->elemCount = numRequired;
	listRepPtr->maxElemCount = newMax;
	listRepPtr->elements = newPtrs;
	ckfree((char *) elemPtrs);
    }

    /*
     * Invalidate and free any old string representation since it no longer
     * reflects the list's internal representation.
     */

    Tcl_InvalidateStringRep(listPtr);
    return TCL_OK;
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
 * the 'ptr2' field of any Tcl_Obj that has been modified is set to
 * NULL.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj*
TclLsetList( interp, listPtr, indexArgPtr, valuePtr )
    Tcl_Interp* interp;		/* Tcl interpreter */
    Tcl_Obj* listPtr;		/* Pointer to the list being modified */
    Tcl_Obj* indexArgPtr;	/* Index or index-list arg to 'lset' */
    Tcl_Obj* valuePtr;		/* Value arg to 'lset' */
{
    int indexCount;		/* Number of indices in the index list */
    Tcl_Obj** indices;		/* Vector of indices in the index list*/

    int duplicated;		/* Flag == 1 if the obj has been
				 * duplicated, 0 otherwise */
    Tcl_Obj* retValuePtr;	/* Pointer to the list to be returned */
    int index;			/* Current index in the list - discarded */
    int result;			/* Status return from library calls */
    Tcl_Obj* subListPtr;	/* Pointer to the current sublist */
    int elemCount;		/* Count of elements in the current sublist */
    Tcl_Obj** elemPtrs;		/* Pointers to elements of current sublist  */
    Tcl_Obj* chainPtr;		/* Pointer to the enclosing sublist
				 * of the current sublist */
    int i;


    /*
     * Determine whether the index arg 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 #23 for details.
     */

    if ( indexArgPtr->typePtr != &tclListType
	 && TclGetIntForIndex( NULL, indexArgPtr, 0, &index ) == TCL_OK ) {

	/*
	 * indexArgPtr designates a single index.
	 */

	return TclLsetFlat( interp, listPtr, 1, &indexArgPtr, valuePtr );

    } else if ( Tcl_ListObjGetElements( NULL, indexArgPtr,
					&indexCount, &indices ) != TCL_OK ) {

	/*
	 * indexArgPtr designates something that is neither an index nor a
	 * well formed list.  Report the error via TclLsetFlat.
	 */

	return TclLsetFlat( interp, listPtr, 1, &indexArgPtr, valuePtr );

    }

    /*
     * At this point, we know that argPtr designates a well formed list,
     * and the 'else if' above has parsed it into indexCount and indices.
     * If there are no indices, simply return 'valuePtr', counting the
     * returned pointer as a reference.
     */

    if ( indexCount == 0 ) {
	Tcl_IncrRefCount( valuePtr );
	return valuePtr;
    }

    /*
     * Duplicate the list arg if necessary.
     */

    if ( Tcl_IsShared( listPtr ) ) {
	duplicated = 1;
	listPtr = Tcl_DuplicateObj( listPtr );
	Tcl_IncrRefCount( listPtr );
    } else {
	duplicated = 0;
    }

    /*
     * It would be tempting simply to go off to TclLsetFlat to finish the
     * processing.  Alas, it is also incorrect!  The problem is that







|







<












<






|
|
<




|

|
|
<





|
<









|
|







|

|
|







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
 * the 'ptr2' field of any Tcl_Obj that has been modified is set to
 * NULL.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj*
TclLsetList(interp, listPtr, indexArgPtr, valuePtr)
    Tcl_Interp* interp;		/* Tcl interpreter */
    Tcl_Obj* listPtr;		/* Pointer to the list being modified */
    Tcl_Obj* indexArgPtr;	/* Index or index-list arg to 'lset' */
    Tcl_Obj* valuePtr;		/* Value arg to 'lset' */
{
    int indexCount;		/* Number of indices in the index list */
    Tcl_Obj** indices;		/* Vector of indices in the index list*/

    int duplicated;		/* Flag == 1 if the obj has been
				 * duplicated, 0 otherwise */
    Tcl_Obj* retValuePtr;	/* Pointer to the list to be returned */
    int index;			/* Current index in the list - discarded */
    int result;			/* Status return from library calls */
    Tcl_Obj* subListPtr;	/* Pointer to the current sublist */
    int elemCount;		/* Count of elements in the current sublist */
    Tcl_Obj** elemPtrs;		/* Pointers to elements of current sublist  */
    Tcl_Obj* chainPtr;		/* Pointer to the enclosing sublist
				 * of the current sublist */
    int i;


    /*
     * Determine whether the index arg 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 #23 for details.
     */

    if (indexArgPtr->typePtr != &tclListType
	    && TclGetIntForIndex(NULL, indexArgPtr, 0, &index) == TCL_OK) {

	/*
	 * indexArgPtr designates a single index.
	 */

	return TclLsetFlat(interp, listPtr, 1, &indexArgPtr, valuePtr);

    } else if (Tcl_ListObjGetElements(NULL, indexArgPtr, &indexCount,
	    &indices) != TCL_OK) {

	/*
	 * indexArgPtr designates something that is neither an index nor a
	 * well formed list.  Report the error via TclLsetFlat.
	 */

	return TclLsetFlat(interp, listPtr, 1, &indexArgPtr, valuePtr);

    }

    /*
     * At this point, we know that argPtr designates a well formed list,
     * and the 'else if' above has parsed it into indexCount and indices.
     * If there are no indices, simply return 'valuePtr', counting the
     * returned pointer as a reference.
     */

    if (indexCount == 0) {
	Tcl_IncrRefCount(valuePtr);
	return valuePtr;
    }

    /*
     * Duplicate the list arg if necessary.
     */

    if (Tcl_IsShared(listPtr)) {
	duplicated = 1;
	listPtr = Tcl_DuplicateObj(listPtr);
	Tcl_IncrRefCount(listPtr);
    } else {
	duplicated = 0;
    }

    /*
     * It would be tempting simply to go off to TclLsetFlat to finish the
     * processing.  Alas, it is also incorrect!  The problem is that
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
    retValuePtr = listPtr;
    chainPtr = NULL;

    /*
     * Handle each index arg by diving into the appropriate sublist
     */

    for ( i = 0; ; ++i ) {

	/*
	 * Take the sublist apart.
	 */

	result = Tcl_ListObjGetElements( interp, listPtr,
					 &elemCount, &elemPtrs );
	if ( result != TCL_OK ) {
	    break;
	}
	listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr;

	/*
	 * Reconstitute the index array
	 */

	result = Tcl_ListObjGetElements( interp, indexArgPtr,
					 &indexCount, &indices );
	if ( result != TCL_OK ) {
	    /* 
	     * Shouldn't be able to get here, because we already
	     * parsed the thing successfully once.
	     */
	    break;
	}

	/*
	 * Determine the index of the requested element.
	 */

	result = TclGetIntForIndex( interp, indices[ i ],
				    (elemCount - 1), &index );
	if ( result != TCL_OK ) {
	    break;
	}
	
	/*
	 * Check that the index is in range.
	 */

	if ( ( index < 0 ) || ( index >= elemCount ) ) {
	    Tcl_SetObjResult( interp,
			      Tcl_NewStringObj( "list index out of range",
						-1 ) );
	    result = TCL_ERROR;
	    break;
	}

	/*
	 * Break the loop after extracting the innermost sublist
	 */

	if ( i >= indexCount-1 ) {
	    result = TCL_OK;
	    break;
	}
	
	/*
	 * Extract the appropriate sublist, and make sure that it is unshared.
	 */

	subListPtr = elemPtrs[ index ];
	if ( Tcl_IsShared( subListPtr ) ) {
	    subListPtr = Tcl_DuplicateObj( subListPtr );
	    result = TclListObjSetElement( interp, listPtr, index,
					    subListPtr );
	    if ( result != TCL_OK ) {
		/* 
		 * We actually shouldn't be able to get here, because
		 * we've already checked everything that TclListObjSetElement
		 * checks. If we were to get here, it would result in leaking
		 * subListPtr.
		 */
		break;
	    }
	}

	/* 
	 * Chain the current sublist onto the linked list of Tcl_Obj's
	 * whose string reps must be spoilt.
	 */

	chainPtr = listPtr;
	listPtr = subListPtr;

    }

    /*
     * Store the new element into the correct slot in the innermost sublist.
     */

    if ( result == TCL_OK ) {
	result = TclListObjSetElement( interp, listPtr, index, valuePtr );
    }

    if ( result == TCL_OK ) {

	listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr;

	/* Spoil all the string reps */
	
	while ( listPtr != NULL ) {
	    subListPtr = (Tcl_Obj *) listPtr->internalRep.twoPtrValue.ptr2;
	    Tcl_InvalidateStringRep( listPtr );
	    listPtr->internalRep.twoPtrValue.ptr2 = NULL;
	    listPtr = subListPtr;
	}

	/* Return the new list if everything worked. */
	
	if ( !duplicated ) {
	    Tcl_IncrRefCount( retValuePtr );
	}
	return retValuePtr;
    }

    /* Clean up the one dangling reference otherwise */

    if ( duplicated ) {
	Tcl_DecrRefCount( retValuePtr );
    }
    return NULL;

}

/*
 *----------------------------------------------------------------------
 *
 * TclLsetFlat --
 *







<
|




|
<
|








|
|
|











|
<
|


|




|
|
|
<








|



|




|
|
|
|
<
|

















<






|
|


|
<



|
|

|





|
|
|






|
|


<







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
    retValuePtr = listPtr;
    chainPtr = NULL;

    /*
     * Handle each index arg by diving into the appropriate sublist
     */


    for (i=0 ; ; i++) {
	/*
	 * Take the sublist apart.
	 */

	result = Tcl_ListObjGetElements(interp, listPtr, &elemCount, &elemPtrs);

	if (result != TCL_OK) {
	    break;
	}
	listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr;

	/*
	 * Reconstitute the index array
	 */

	result = Tcl_ListObjGetElements(interp, indexArgPtr, &indexCount,
		&indices);
	if (result != TCL_OK) {
	    /* 
	     * Shouldn't be able to get here, because we already
	     * parsed the thing successfully once.
	     */
	    break;
	}

	/*
	 * Determine the index of the requested element.
	 */

	result = TclGetIntForIndex(interp, indices[i], elemCount-1, &index);

	if (result != TCL_OK) {
	    break;
	}

	/*
	 * Check that the index is in range.
	 */

	if (index<0 || index>=elemCount) {
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("list index out of range", -1));

	    result = TCL_ERROR;
	    break;
	}

	/*
	 * Break the loop after extracting the innermost sublist
	 */

	if (i >= indexCount-1) {
	    result = TCL_OK;
	    break;
	}

	/*
	 * Extract the appropriate sublist, and make sure that it is unshared.
	 */

	subListPtr = elemPtrs[index];
	if (Tcl_IsShared(subListPtr)) {
	    subListPtr = Tcl_DuplicateObj(subListPtr);
	    result = TclListObjSetElement(interp, listPtr, index, subListPtr);

	    if (result != TCL_OK) {
		/* 
		 * We actually shouldn't be able to get here, because
		 * we've already checked everything that TclListObjSetElement
		 * checks. If we were to get here, it would result in leaking
		 * subListPtr.
		 */
		break;
	    }
	}

	/* 
	 * Chain the current sublist onto the linked list of Tcl_Obj's
	 * whose string reps must be spoilt.
	 */

	chainPtr = listPtr;
	listPtr = subListPtr;

    }

    /*
     * Store the new element into the correct slot in the innermost sublist.
     */

    if (result == TCL_OK) {
	result = TclListObjSetElement(interp, listPtr, index, valuePtr);
    }

    if (result == TCL_OK) {

	listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr;

	/* Spoil all the string reps */

	while (listPtr != NULL) {
	    subListPtr = (Tcl_Obj *) listPtr->internalRep.twoPtrValue.ptr2;
	    Tcl_InvalidateStringRep(listPtr);
	    listPtr->internalRep.twoPtrValue.ptr2 = NULL;
	    listPtr = subListPtr;
	}

	/* Return the new list if everything worked. */

	if (!duplicated) {
	    Tcl_IncrRefCount(retValuePtr);
	}
	return retValuePtr;
    }

    /* Clean up the one dangling reference otherwise */

    if (duplicated) {
	Tcl_DecrRefCount(retValuePtr);
    }
    return NULL;

}

/*
 *----------------------------------------------------------------------
 *
 * TclLsetFlat --
 *
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
 * the 'ptr2' field of any Tcl_Obj that has been modified is set to
 * NULL.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj*
TclLsetFlat( interp, listPtr, indexCount, indexArray, valuePtr )
    Tcl_Interp* interp;		/* Tcl interpreter */
    Tcl_Obj* listPtr;		/* Pointer to the list being modified */
    int indexCount;		/* Number of index args */
    Tcl_Obj *CONST indexArray[];
				/* Index args */
    Tcl_Obj* valuePtr;		/* Value arg to 'lset' */
{

    int duplicated;		/* Flag == 1 if the obj has been
				 * duplicated, 0 otherwise */
    Tcl_Obj* retValuePtr;	/* Pointer to the list to be returned */

    int elemCount;		/* Length of one sublist being changed */
    Tcl_Obj** elemPtrs;		/* Pointers to the elements of a sublist */

    Tcl_Obj* subListPtr;	/* Pointer to the current sublist */

    int index;			/* Index of the element to replace in the
				 * current sublist */
    Tcl_Obj* chainPtr;		/* Pointer to the enclosing list of
				 * the current sublist. */

    int result;			/* Status return from library calls */



    int i;

    /*
     * If there are no indices, then simply return the new value,
     * counting the returned pointer as a reference
     */

    if ( indexCount == 0 ) {
	Tcl_IncrRefCount( valuePtr );
	return valuePtr;
    }

    /*
     * If the list is shared, make a private copy.
     */

    if ( Tcl_IsShared( listPtr ) ) {
	duplicated = 1;
	listPtr = Tcl_DuplicateObj( listPtr );
	Tcl_IncrRefCount( listPtr );
    } else {
	duplicated = 0;
    }

    /*
     * Anchor the linked list of Tcl_Obj's whose string reps must be
     * invalidated if the operation succeeds.
     */

    retValuePtr = listPtr;
    chainPtr = NULL;

    /*
     * Handle each index arg by diving into the appropriate sublist
     */

    for ( i = 0; ; ++i ) {

	/*
	 * Take the sublist apart.
	 */

	result = Tcl_ListObjGetElements( interp, listPtr,
					 &elemCount, &elemPtrs );
	if ( result != TCL_OK ) {
	    break;
	}
	listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr;

	/*
	 * Determine the index of the requested element.
	 */

	result = TclGetIntForIndex( interp, indexArray[ i ],
				    (elemCount - 1), &index );
	if ( result != TCL_OK ) {
	    break;
	}
	
	/*
	 * Check that the index is in range.
	 */

	if ( ( index < 0 ) || ( index >= elemCount ) ) {
	    Tcl_SetObjResult( interp,
			      Tcl_NewStringObj( "list index out of range",
						-1 ) );
	    result = TCL_ERROR;
	    break;
	}

	/*
	 * Break the loop after extracting the innermost sublist
	 */

	if ( i >= indexCount-1 ) {
	    result = TCL_OK;
	    break;
	}
	
	/*
	 * Extract the appropriate sublist, and make sure that it is unshared.
	 */

	subListPtr = elemPtrs[ index ];
	if ( Tcl_IsShared( subListPtr ) ) {
	    subListPtr = Tcl_DuplicateObj( subListPtr );
	    result = TclListObjSetElement( interp, listPtr, index,
					    subListPtr );
	    if ( result != TCL_OK ) {
		/* 
		 * We actually shouldn't be able to get here.
		 * If we do, it would result in leaking subListPtr,
		 * but everything's been validated already; the error
		 * exit from TclListObjSetElement should never happen.
		 */
		break;
	    }
	}

	/* 
	 * Chain the current sublist onto the linked list of Tcl_Obj's
	 * whose string reps must be spoilt.
	 */

	chainPtr = listPtr;
	listPtr = subListPtr;

    }

    /* Store the result in the list element */

    if ( result == TCL_OK ) {
	result = TclListObjSetElement( interp, listPtr, index, valuePtr );
    }

    if ( result == TCL_OK ) {

	listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr;

	/* Spoil all the string reps */
	
	while ( listPtr != NULL ) {
	    subListPtr = (Tcl_Obj *) listPtr->internalRep.twoPtrValue.ptr2;
	    Tcl_InvalidateStringRep( listPtr );
	    listPtr->internalRep.twoPtrValue.ptr2 = NULL;
	    listPtr = subListPtr;
	}

	/* Return the new list if everything worked. */
	
	if ( !duplicated ) {
	    Tcl_IncrRefCount( retValuePtr );
	}
	return retValuePtr;
    }

    /* Clean up the one dangling reference otherwise */

    if ( duplicated ) {
	Tcl_DecrRefCount( retValuePtr );
    }
    return NULL;

}

/*
 *----------------------------------------------------------------------
 *
 * TclListObjSetElement --
 *







|







<



<


<

<




<

<
<
<







|
|







|

|
|
















<
|




|
<
|








|
<
|


|




|
|
|
<








|



|




|
|
|
|
<
|

















<




|
|


|
<



|
|

|





|
|
|






|
|


<







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
 * the 'ptr2' field of any Tcl_Obj that has been modified is set to
 * NULL.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj*
TclLsetFlat(interp, listPtr, indexCount, indexArray, valuePtr)
    Tcl_Interp* interp;		/* Tcl interpreter */
    Tcl_Obj* listPtr;		/* Pointer to the list being modified */
    int indexCount;		/* Number of index args */
    Tcl_Obj *CONST indexArray[];
				/* Index args */
    Tcl_Obj* valuePtr;		/* Value arg to 'lset' */
{

    int duplicated;		/* Flag == 1 if the obj has been
				 * duplicated, 0 otherwise */
    Tcl_Obj* retValuePtr;	/* Pointer to the list to be returned */

    int elemCount;		/* Length of one sublist being changed */
    Tcl_Obj** elemPtrs;		/* Pointers to the elements of a sublist */

    Tcl_Obj* subListPtr;	/* Pointer to the current sublist */

    int index;			/* Index of the element to replace in the
				 * current sublist */
    Tcl_Obj* chainPtr;		/* Pointer to the enclosing list of
				 * the current sublist. */

    int result;			/* Status return from library calls */



    int i;

    /*
     * If there are no indices, then simply return the new value,
     * counting the returned pointer as a reference
     */

    if (indexCount == 0) {
	Tcl_IncrRefCount(valuePtr);
	return valuePtr;
    }

    /*
     * If the list is shared, make a private copy.
     */

    if (Tcl_IsShared(listPtr)) {
	duplicated = 1;
	listPtr = Tcl_DuplicateObj(listPtr);
	Tcl_IncrRefCount(listPtr);
    } else {
	duplicated = 0;
    }

    /*
     * Anchor the linked list of Tcl_Obj's whose string reps must be
     * invalidated if the operation succeeds.
     */

    retValuePtr = listPtr;
    chainPtr = NULL;

    /*
     * Handle each index arg by diving into the appropriate sublist
     */


    for (i=0 ; ; i++) {
	/*
	 * Take the sublist apart.
	 */

	result = Tcl_ListObjGetElements(interp, listPtr, &elemCount, &elemPtrs);

	if (result != TCL_OK) {
	    break;
	}
	listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr;

	/*
	 * Determine the index of the requested element.
	 */

	result = TclGetIntForIndex(interp, indexArray[i], elemCount-1, &index);

	if (result != TCL_OK) {
	    break;
	}

	/*
	 * Check that the index is in range.
	 */

	if (index<0 || index>=elemCount) {
	    Tcl_SetObjResult(interp,
		    Tcl_NewStringObj("list index out of range", -1));

	    result = TCL_ERROR;
	    break;
	}

	/*
	 * Break the loop after extracting the innermost sublist
	 */

	if (i >= indexCount-1) {
	    result = TCL_OK;
	    break;
	}

	/*
	 * Extract the appropriate sublist, and make sure that it is unshared.
	 */

	subListPtr = elemPtrs[index];
	if (Tcl_IsShared(subListPtr)) {
	    subListPtr = Tcl_DuplicateObj(subListPtr);
	    result = TclListObjSetElement(interp, listPtr, index, subListPtr);

	    if (result != TCL_OK) {
		/* 
		 * We actually shouldn't be able to get here.
		 * If we do, it would result in leaking subListPtr,
		 * but everything's been validated already; the error
		 * exit from TclListObjSetElement should never happen.
		 */
		break;
	    }
	}

	/* 
	 * Chain the current sublist onto the linked list of Tcl_Obj's
	 * whose string reps must be spoilt.
	 */

	chainPtr = listPtr;
	listPtr = subListPtr;

    }

    /* Store the result in the list element */

    if (result == TCL_OK) {
	result = TclListObjSetElement(interp, listPtr, index, valuePtr);
    }

    if (result == TCL_OK) {

	listPtr->internalRep.twoPtrValue.ptr2 = (VOID *) chainPtr;

	/* Spoil all the string reps */

	while (listPtr != NULL) {
	    subListPtr = (Tcl_Obj *) listPtr->internalRep.twoPtrValue.ptr2;
	    Tcl_InvalidateStringRep(listPtr);
	    listPtr->internalRep.twoPtrValue.ptr2 = NULL;
	    listPtr = subListPtr;
	}

	/* Return the new list if everything worked. */

	if (!duplicated) {
	    Tcl_IncrRefCount(retValuePtr);
	}
	return retValuePtr;
    }

    /* Clean up the one dangling reference otherwise */

    if (duplicated) {
	Tcl_DecrRefCount(retValuePtr);
    }
    return NULL;

}

/*
 *----------------------------------------------------------------------
 *
 * TclListObjSetElement --
 *
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
 *	an element outside the range [0..listLength-1], where
 *	listLength is the count of elements in the list object designated
 *	by listPtr, TCL_ERROR is returned and an error message is left
 *	in the interpreter result.
 *
 * Side effects:
 *
 *	Panics if listPtr designates a shared object.  Otherwise, attempts
 *	to convert it to a list.  Decrements the ref count of the object
 *	at the specified index within the list, replaces with the
 *	object designated by valuePtr, and increments the ref count
 *	of the replacement object.  
 *
 * It is the caller's responsibility to invalidate the string
 * representation of the object.
 *
 *----------------------------------------------------------------------
 */

int
TclListObjSetElement( interp, listPtr, index, valuePtr )
    Tcl_Interp* interp;		/* Tcl interpreter; used for error reporting
				 * if not NULL */
    Tcl_Obj* listPtr;		/* List object in which element should be
				 * stored */
    int index;			/* Index of element to store */
    Tcl_Obj* valuePtr;		/* Tcl object to store in the designated
				 * list element */
{
    int result;			/* Return value from this function */
    List* listRepPtr;		/* Internal representation of the list
				 * being modified */
    Tcl_Obj** elemPtrs;		/* Pointers to elements of the list */
    int elemCount;		/* Number of elements in the list */

    /* Ensure that the listPtr parameter designates an unshared list */

    if ( Tcl_IsShared( listPtr ) ) {
	panic( "Tcl_ListObjSetElement called with shared object" );
    }
    if ( listPtr->typePtr != &tclListType ) {
	result = SetListFromAny( interp, listPtr );
	if ( result != TCL_OK ) {
	    return result;
	}
    }
    listRepPtr = (List*) listPtr->internalRep.twoPtrValue.ptr1;
    elemPtrs = listRepPtr->elements;
    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 ) );
	    return TCL_ERROR;
	}
    }

    /* Add a reference to the new list element */

    Tcl_IncrRefCount( valuePtr );

    /* Remove a reference from the old list element */

    Tcl_DecrRefCount( elemPtrs[ index ] );

    /* Stash the new object in the list */

    elemPtrs[ index ] = valuePtr;

    return TCL_OK;
    
}

/*
 *----------------------------------------------------------------------
 *
 * FreeListInternalRep --
 *







|
|
|
|









|
















|
|

|
|
|









|
|
|
|
<






|



|



|


<







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
 *	an element outside the range [0..listLength-1], where
 *	listLength is the count of elements in the list object designated
 *	by listPtr, TCL_ERROR is returned and an error message is left
 *	in the interpreter result.
 *
 * Side effects:
 *
 *	Tcl_Panic if listPtr designates a shared object.  Otherwise,
 *	attempts to convert it to a list.  Decrements the ref count of
 *	the object at the specified index within the list, replaces with
 *	the object designated by valuePtr, and increments the ref count
 *	of the replacement object.  
 *
 * It is the caller's responsibility to invalidate the string
 * representation of the object.
 *
 *----------------------------------------------------------------------
 */

int
TclListObjSetElement(interp, listPtr, index, valuePtr)
    Tcl_Interp* interp;		/* Tcl interpreter; used for error reporting
				 * if not NULL */
    Tcl_Obj* listPtr;		/* List object in which element should be
				 * stored */
    int index;			/* Index of element to store */
    Tcl_Obj* valuePtr;		/* Tcl object to store in the designated
				 * list element */
{
    int result;			/* Return value from this function */
    List* listRepPtr;		/* Internal representation of the list
				 * being modified */
    Tcl_Obj** elemPtrs;		/* Pointers to elements of the list */
    int elemCount;		/* Number of elements in the list */

    /* Ensure that the listPtr parameter designates an unshared list */

    if (Tcl_IsShared(listPtr)) {
	Tcl_Panic("Tcl_ListObjSetElement called with shared object");
    }
    if (listPtr->typePtr != &tclListType) {
	result = SetListFromAny(interp, listPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }
    listRepPtr = (List*) listPtr->internalRep.twoPtrValue.ptr1;
    elemPtrs = listRepPtr->elements;
    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));

	    return TCL_ERROR;
	}
    }

    /* Add a reference to the new list element */

    Tcl_IncrRefCount(valuePtr);

    /* Remove a reference from the old list element */

    Tcl_DecrRefCount(elemPtrs[index]);

    /* Stash the new object in the list */

    elemPtrs[index] = valuePtr;

    return TCL_OK;

}

/*
 *----------------------------------------------------------------------
 *
 * FreeListInternalRep --
 *
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
    Tcl_Obj *listPtr;		/* List object with internal rep to free. */
{
    register List *listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
    register Tcl_Obj **elemPtrs = listRepPtr->elements;
    register Tcl_Obj *objPtr;
    int numElems = listRepPtr->elemCount;
    int i;
    
    for (i = 0;  i < numElems;  i++) {
	objPtr = elemPtrs[i];
	Tcl_DecrRefCount(objPtr);
    }
    ckfree((char *) elemPtrs);
    ckfree((char *) listRepPtr);








|







1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
    Tcl_Obj *listPtr;		/* List object with internal rep to free. */
{
    register List *listRepPtr = (List *) listPtr->internalRep.twoPtrValue.ptr1;
    register Tcl_Obj **elemPtrs = listRepPtr->elements;
    register Tcl_Obj *objPtr;
    int numElems = listRepPtr->elemCount;
    int i;

    for (i = 0;  i < numElems;  i++) {
	objPtr = elemPtrs[i];
	Tcl_DecrRefCount(objPtr);
    }
    ckfree((char *) elemPtrs);
    ckfree((char *) listRepPtr);

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
    int i;

    /*
     * Allocate a new List structure that points to "srcPtr"s element
     * objects. Increment the ref counts for those (now shared) element
     * objects.
     */
    
    copyElemPtrs = (Tcl_Obj **)
	ckalloc((unsigned) maxElems * sizeof(Tcl_Obj *));
    for (i = 0;  i < numElems;  i++) {
	copyElemPtrs[i] = srcElemPtrs[i];
	Tcl_IncrRefCount(copyElemPtrs[i]);
    }
    
    copyListRepPtr = (List *) ckalloc(sizeof(List));
    copyListRepPtr->maxElemCount = maxElems;
    copyListRepPtr->elemCount    = numElems;
    copyListRepPtr->elements     = copyElemPtrs;
    
    copyPtr->internalRep.twoPtrValue.ptr1 = (VOID *) copyListRepPtr;
    copyPtr->internalRep.twoPtrValue.ptr2 = NULL;
    copyPtr->typePtr = &tclListType;
}

/*
 *----------------------------------------------------------------------







|






|




|







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
    int i;

    /*
     * Allocate a new List structure that points to "srcPtr"s element
     * objects. Increment the ref counts for those (now shared) element
     * objects.
     */

    copyElemPtrs = (Tcl_Obj **)
	ckalloc((unsigned) maxElems * sizeof(Tcl_Obj *));
    for (i = 0;  i < numElems;  i++) {
	copyElemPtrs[i] = srcElemPtrs[i];
	Tcl_IncrRefCount(copyElemPtrs[i]);
    }

    copyListRepPtr = (List *) ckalloc(sizeof(List));
    copyListRepPtr->maxElemCount = maxElems;
    copyListRepPtr->elemCount    = numElems;
    copyListRepPtr->elements     = copyElemPtrs;

    copyPtr->internalRep.twoPtrValue.ptr1 = (VOID *) copyListRepPtr;
    copyPtr->internalRep.twoPtrValue.ptr2 = NULL;
    copyPtr->typePtr = &tclListType;
}

/*
 *----------------------------------------------------------------------
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
	    ckfree((char *) elemPtrs);
	    return result;
	}
	if (elemStart >= limit) {
	    break;
	}
	if (i > estCount) {
	    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((unsigned) elemSize + 1);
	if (hasBrace) {
	    memcpy((VOID *) s, (VOID *) 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 = (List *) ckalloc(sizeof(List));
    listRepPtr->maxElemCount = estCount;
    listRepPtr->elemCount    = i;
    listRepPtr->elements     = elemPtrs;







|














|

|
|
|







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
	    ckfree((char *) elemPtrs);
	    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((unsigned) elemSize + 1);
	if (hasBrace) {
	    memcpy((VOID *) s, (VOID *) 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 = (List *) ckalloc(sizeof(List));
    listRepPtr->maxElemCount = estCount;
    listRepPtr->elemCount    = i;
    listRepPtr->elements     = elemPtrs;
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
     * Pass 2: copy into string rep buffer.
     */

    listPtr->bytes = ckalloc((unsigned) listPtr->length);
    dst = listPtr->bytes;
    for (i = 0; i < numElems; i++) {
	elem = Tcl_GetStringFromObj(listRepPtr->elements[i], &length);
	dst += Tcl_ConvertCountedElement(elem, length, dst, 
		flagPtr[i] | (i==0 ? 0 : TCL_DONT_QUOTE_HASH) );
	*dst = ' ';
	dst++;
    }
    if (flagPtr != localFlags) {
	ckfree((char *) flagPtr);
    }
    if (dst == listPtr->bytes) {







|
|







1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
     * Pass 2: copy into string rep buffer.
     */

    listPtr->bytes = ckalloc((unsigned) listPtr->length);
    dst = listPtr->bytes;
    for (i = 0; i < numElems; i++) {
	elem = Tcl_GetStringFromObj(listRepPtr->elements[i], &length);
	dst += Tcl_ConvertCountedElement(elem, length, dst,
		flagPtr[i] | (i==0 ? 0 : TCL_DONT_QUOTE_HASH));
	*dst = ' ';
	dst++;
    }
    if (flagPtr != localFlags) {
	ckfree((char *) flagPtr);
    }
    if (dst == listPtr->bytes) {
Changes to generic/tclLiteral.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *	that appears in tclHash.c.
 *
 * Copyright (c) 1997-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.
 *
 * RCS: @(#) $Id: tclLiteral.c,v 1.11 2001/10/11 22:28:01 msofer Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"
#include "tclPort.h"
/*
 * When there are this many entries per bucket, on average, rebuild







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *	that appears in tclHash.c.
 *
 * Copyright (c) 1997-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.
 *
 * RCS: @(#) $Id: tclLiteral.c,v 1.11.8.1 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"
#include "tclPort.h"
/*
 * When there are this many entries per bucket, on average, rebuild
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

void
TclInitLiteralTable(tablePtr)
    register LiteralTable *tablePtr; /* Pointer to table structure, which
				      * is supplied by the caller. */
{
#if (TCL_SMALL_HASH_TABLE != 4) 
    panic("TclInitLiteralTable: TCL_SMALL_HASH_TABLE is %d, not 4\n",
	    TCL_SMALL_HASH_TABLE);
#endif
    
    tablePtr->buckets = tablePtr->staticBuckets;
    tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0;
    tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
    tablePtr->numBuckets = TCL_SMALL_HASH_TABLE;







|







59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

void
TclInitLiteralTable(tablePtr)
    register LiteralTable *tablePtr; /* Pointer to table structure, which
				      * is supplied by the caller. */
{
#if (TCL_SMALL_HASH_TABLE != 4) 
    Tcl_Panic("TclInitLiteralTable: TCL_SMALL_HASH_TABLE is %d, not 4\n",
	    TCL_SMALL_HASH_TABLE);
#endif
    
    tablePtr->buckets = tablePtr->staticBuckets;
    tablePtr->staticBuckets[0] = tablePtr->staticBuckets[1] = 0;
    tablePtr->staticBuckets[2] = tablePtr->staticBuckets[3] = 0;
    tablePtr->numBuckets = TCL_SMALL_HASH_TABLE;
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
	    
	    if (onHeap) {
		ckfree(bytes);
	    }
	    objIndex = AddLocalLiteralEntry(envPtr, globalPtr, localHash);
#ifdef TCL_COMPILE_DEBUG
	    if (globalPtr->refCount < 1) {
		panic("TclRegisterLiteral: global literal \"%.*s\" had bad refCount %d",
			(length>60? 60 : length), bytes,
			globalPtr->refCount);
	    }
	    TclVerifyLocalLiteralTable(envPtr);
#endif /*TCL_COMPILE_DEBUG*/ 
	    return objIndex;
	}







|







238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
	    
	    if (onHeap) {
		ckfree(bytes);
	    }
	    objIndex = AddLocalLiteralEntry(envPtr, globalPtr, localHash);
#ifdef TCL_COMPILE_DEBUG
	    if (globalPtr->refCount < 1) {
		Tcl_Panic("TclRegisterLiteral: global literal \"%.*s\" had bad refCount %d",
			(length>60? 60 : length), bytes,
			globalPtr->refCount);
	    }
	    TclVerifyLocalLiteralTable(envPtr);
#endif /*TCL_COMPILE_DEBUG*/ 
	    return objIndex;
	}
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
		objPtr->typePtr = &tclIntType;
	    }
	}
    }
    
#ifdef TCL_COMPILE_DEBUG
    if (TclLookupLiteralEntry((Tcl_Interp *) iPtr, objPtr) != NULL) {
	panic("TclRegisterLiteral: literal \"%.*s\" found globally but shouldn't be",
	        (length>60? 60 : length), bytes);
    }
#endif

    globalPtr = (LiteralEntry *) ckalloc((unsigned) sizeof(LiteralEntry));
    globalPtr->objPtr = objPtr;
    globalPtr->refCount = 0;







|







278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
		objPtr->typePtr = &tclIntType;
	    }
	}
    }
    
#ifdef TCL_COMPILE_DEBUG
    if (TclLookupLiteralEntry((Tcl_Interp *) iPtr, objPtr) != NULL) {
	Tcl_Panic("TclRegisterLiteral: literal \"%.*s\" found globally but shouldn't be",
	        (length>60? 60 : length), bytes);
    }
#endif

    globalPtr = (LiteralEntry *) ckalloc((unsigned) sizeof(LiteralEntry));
    globalPtr->objPtr = objPtr;
    globalPtr->refCount = 0;
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
		if ((entryPtr == globalPtr)
		        && (entryPtr->objPtr == objPtr)) {
		    found = 1;
		}
	    }
	}
	if (!found) {
	    panic("TclRegisterLiteral: literal \"%.*s\" wasn't global",
	            (length>60? 60 : length), bytes);
	}
    }
#endif /*TCL_COMPILE_DEBUG*/
#ifdef TCL_COMPILE_STATS   
    iPtr->stats.numLiteralsCreated++;
    iPtr->stats.totalLitStringBytes   += (double) (length + 1);







|







317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
		if ((entryPtr == globalPtr)
		        && (entryPtr->objPtr == objPtr)) {
		    found = 1;
		}
	    }
	}
	if (!found) {
	    Tcl_Panic("TclRegisterLiteral: literal \"%.*s\" wasn't global",
	            (length>60? 60 : length), bytes);
	}
    }
#endif /*TCL_COMPILE_DEBUG*/
#ifdef TCL_COMPILE_STATS   
    iPtr->stats.numLiteralsCreated++;
    iPtr->stats.totalLitStringBytes   += (double) (length + 1);
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
		if (localPtr->objPtr == globalPtr->objPtr) {
		    found = 1;
		}
	    }
	}
	if (!found) {
	    bytes = Tcl_GetStringFromObj(globalPtr->objPtr, &length);
	    panic("AddLocalLiteralEntry: literal \"%.*s\" wasn't found locally",
	            (length>60? 60 : length), bytes);
	}
    }
#endif /*TCL_COMPILE_DEBUG*/
    return objIndex;
}








|







559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
		if (localPtr->objPtr == globalPtr->objPtr) {
		    found = 1;
		}
	    }
	}
	if (!found) {
	    bytes = Tcl_GetStringFromObj(globalPtr->objPtr, &length);
	    Tcl_Panic("AddLocalLiteralEntry: literal \"%.*s\" wasn't found locally",
	            (length>60? 60 : length), bytes);
	}
    }
#endif /*TCL_COMPILE_DEBUG*/
    return objIndex;
}

955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
 *
 *	Check a CompileEnv's local literal table for consistency.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Panics if problems are found.
 *
 *----------------------------------------------------------------------
 */

void
TclVerifyLocalLiteralTable(envPtr)
    CompileEnv *envPtr;		/* Points to CompileEnv whose literal







|







955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
 *
 *	Check a CompileEnv's local literal table for consistency.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Tcl_Panic if problems are found.
 *
 *----------------------------------------------------------------------
 */

void
TclVerifyLocalLiteralTable(envPtr)
    CompileEnv *envPtr;		/* Points to CompileEnv whose literal
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
    count = 0;
    for (i = 0;  i < localTablePtr->numBuckets;  i++) {
	for (localPtr = localTablePtr->buckets[i];
	        localPtr != NULL;  localPtr = localPtr->nextPtr) {
	    count++;
	    if (localPtr->refCount != -1) {
		bytes = Tcl_GetStringFromObj(localPtr->objPtr, &length);
		panic("TclVerifyLocalLiteralTable: local literal \"%.*s\" had bad refCount %d",
		        (length>60? 60 : length), bytes,
		        localPtr->refCount);
	    }
	    if (TclLookupLiteralEntry((Tcl_Interp *) envPtr->iPtr,
		    localPtr->objPtr) == NULL) {
		bytes = Tcl_GetStringFromObj(localPtr->objPtr, &length);
		panic("TclVerifyLocalLiteralTable: local literal \"%.*s\" is not global",
		         (length>60? 60 : length), bytes);
	    }
	    if (localPtr->objPtr->bytes == NULL) {
		panic("TclVerifyLocalLiteralTable: literal has NULL string rep");
	    }
	}
    }
    if (count != localTablePtr->numEntries) {
	panic("TclVerifyLocalLiteralTable: local literal table had %d entries, should be %d",
	      count, localTablePtr->numEntries);
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TclVerifyGlobalLiteralTable --
 *
 *	Check an interpreter's global literal table literal for consistency.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Panics if problems are found.
 *
 *----------------------------------------------------------------------
 */

void
TclVerifyGlobalLiteralTable(iPtr)
    Interp *iPtr;		/* Points to interpreter whose global







|






|



|




|















|







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
    count = 0;
    for (i = 0;  i < localTablePtr->numBuckets;  i++) {
	for (localPtr = localTablePtr->buckets[i];
	        localPtr != NULL;  localPtr = localPtr->nextPtr) {
	    count++;
	    if (localPtr->refCount != -1) {
		bytes = Tcl_GetStringFromObj(localPtr->objPtr, &length);
		Tcl_Panic("TclVerifyLocalLiteralTable: local literal \"%.*s\" had bad refCount %d",
		        (length>60? 60 : length), bytes,
		        localPtr->refCount);
	    }
	    if (TclLookupLiteralEntry((Tcl_Interp *) envPtr->iPtr,
		    localPtr->objPtr) == NULL) {
		bytes = Tcl_GetStringFromObj(localPtr->objPtr, &length);
		Tcl_Panic("TclVerifyLocalLiteralTable: local literal \"%.*s\" is not global",
		         (length>60? 60 : length), bytes);
	    }
	    if (localPtr->objPtr->bytes == NULL) {
		Tcl_Panic("TclVerifyLocalLiteralTable: literal has NULL string rep");
	    }
	}
    }
    if (count != localTablePtr->numEntries) {
	Tcl_Panic("TclVerifyLocalLiteralTable: local literal table had %d entries, should be %d",
	      count, localTablePtr->numEntries);
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TclVerifyGlobalLiteralTable --
 *
 *	Check an interpreter's global literal table literal for consistency.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Tcl_Panic if problems are found.
 *
 *----------------------------------------------------------------------
 */

void
TclVerifyGlobalLiteralTable(iPtr)
    Interp *iPtr;		/* Points to interpreter whose global
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
    count = 0;
    for (i = 0;  i < globalTablePtr->numBuckets;  i++) {
	for (globalPtr = globalTablePtr->buckets[i];
	        globalPtr != NULL;  globalPtr = globalPtr->nextPtr) {
	    count++;
	    if (globalPtr->refCount < 1) {
		bytes = Tcl_GetStringFromObj(globalPtr->objPtr, &length);
		panic("TclVerifyGlobalLiteralTable: global literal \"%.*s\" had bad refCount %d",
		        (length>60? 60 : length), bytes,
		        globalPtr->refCount);
	    }
	    if (globalPtr->objPtr->bytes == NULL) {
		panic("TclVerifyGlobalLiteralTable: literal has NULL string rep");
	    }
	}
    }
    if (count != globalTablePtr->numEntries) {
	panic("TclVerifyGlobalLiteralTable: global literal table had %d entries, should be %d",
	      count, globalTablePtr->numEntries);
    }
}
#endif /*TCL_COMPILE_DEBUG*/







|




|




|




1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
    count = 0;
    for (i = 0;  i < globalTablePtr->numBuckets;  i++) {
	for (globalPtr = globalTablePtr->buckets[i];
	        globalPtr != NULL;  globalPtr = globalPtr->nextPtr) {
	    count++;
	    if (globalPtr->refCount < 1) {
		bytes = Tcl_GetStringFromObj(globalPtr->objPtr, &length);
		Tcl_Panic("TclVerifyGlobalLiteralTable: global literal \"%.*s\" had bad refCount %d",
		        (length>60? 60 : length), bytes,
		        globalPtr->refCount);
	    }
	    if (globalPtr->objPtr->bytes == NULL) {
		Tcl_Panic("TclVerifyGlobalLiteralTable: literal has NULL string rep");
	    }
	}
    }
    if (count != globalTablePtr->numEntries) {
	Tcl_Panic("TclVerifyGlobalLiteralTable: global literal table had %d entries, should be %d",
	      count, globalTablePtr->numEntries);
    }
}
#endif /*TCL_COMPILE_DEBUG*/
Changes to generic/tclNamesp.c.
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 *   Michael J. McLennan
 *   Bell Labs Innovations for Lucent Technologies
 *   mmclennan@lucent.com
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclNamesp.c,v 1.31.4.2 2003/10/16 02:28:02 dgp Exp $
 */

#include "tclInt.h"

/*
 * Flag passed to TclGetNamespaceForQualName to indicate that it should
 * search for a namespace rather than a command or variable inside a







|







17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 *   Michael J. McLennan
 *   Bell Labs Innovations for Lucent Technologies
 *   mmclennan@lucent.com
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclNamesp.c,v 1.31.4.3 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"

/*
 * Flag passed to TclGetNamespaceForQualName to indicate that it should
 * search for a namespace rather than a command or variable inside a
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
    register Namespace *nsPtr;

    if (namespacePtr == NULL) {
	nsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp);
    } else {
        nsPtr = (Namespace *) namespacePtr;
        if (nsPtr->flags & NS_DEAD) {
	    panic("Trying to push call frame for dead namespace");
	    /*NOTREACHED*/
        }
    }

    nsPtr->activationCount++;
    framePtr->nsPtr = nsPtr;
    framePtr->isProcCallFrame = isProcCallFrame;







|







420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
    register Namespace *nsPtr;

    if (namespacePtr == NULL) {
	nsPtr = (Namespace *) Tcl_GetCurrentNamespace(interp);
    } else {
        nsPtr = (Namespace *) namespacePtr;
        if (nsPtr->flags & NS_DEAD) {
	    Tcl_Panic("Trying to push call frame for dead namespace");
	    /*NOTREACHED*/
        }
    }

    nsPtr->activationCount++;
    framePtr->nsPtr = nsPtr;
    framePtr->isProcCallFrame = isProcCallFrame;
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
	    ckfree((char *) refPtr);
	    ckfree((char *) dataPtr);
	    return;
	}
	prevPtr = refPtr;
    }
	
    panic("DeleteImportedCmd: did not find cmd in real cmd's list of import references");
}

/*
 *----------------------------------------------------------------------
 *
 * TclGetNamespaceForQualName --
 *







|







1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
	    ckfree((char *) refPtr);
	    ckfree((char *) dataPtr);
	    return;
	}
	prevPtr = refPtr;
    }
	
    Tcl_Panic("DeleteImportedCmd: did not find cmd in real cmd's list of import references");
}

/*
 *----------------------------------------------------------------------
 *
 * TclGetNamespaceForQualName --
 *
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
		        (Tcl_Namespace *) nsPtr, /*isProcCallFrame*/ 0);

                nsPtr = (Namespace *) Tcl_CreateNamespace(interp, nsName,
		        (ClientData) NULL, (Tcl_NamespaceDeleteProc *) NULL);
                Tcl_PopCallFrame(interp);

                if (nsPtr == NULL) {
                    panic("Could not create namespace '%s'", nsName);
                }
            } else {		/* namespace not found and wasn't created */
                nsPtr = NULL;
            }
        }

        /*







|







1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
		        (Tcl_Namespace *) nsPtr, /*isProcCallFrame*/ 0);

                nsPtr = (Namespace *) Tcl_CreateNamespace(interp, nsName,
		        (ClientData) NULL, (Tcl_NamespaceDeleteProc *) NULL);
                Tcl_PopCallFrame(interp);

                if (nsPtr == NULL) {
                    Tcl_Panic("Could not create namespace '%s'", nsName);
                }
            } else {		/* namespace not found and wasn't created */
                nsPtr = NULL;
            }
        }

        /*
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
	     */
	    ensemblePtr->nsPtr->exportLookupEpoch++;
	    return TCL_OK;
	}
    }

    default:
	panic("unexpected ensemble command");
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *







|







4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
	     */
	    ensemblePtr->nsPtr->exportLookupEpoch++;
	    return TCL_OK;
	}
    }

    default:
	Tcl_Panic("unexpected ensemble command");
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
	    /*
	     * The subcommand is not a prefix of anything, so bail out!
	     */
	    goto unknownOrAmbiguousSubcommand;
	}
	hPtr = Tcl_FindHashEntry(&ensemblePtr->subcommandTable, fullName);
	if (hPtr == NULL) {
	    panic("full name %s not found in supposedly synchronized hash",
		    fullName);
	}
	prefixObj = (Tcl_Obj *) Tcl_GetHashValue(hPtr);

	/*
	 * Cache for later in the subcommand object.
	 */







|







4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
	    /*
	     * The subcommand is not a prefix of anything, so bail out!
	     */
	    goto unknownOrAmbiguousSubcommand;
	}
	hPtr = Tcl_FindHashEntry(&ensemblePtr->subcommandTable, fullName);
	if (hPtr == NULL) {
	    Tcl_Panic("full name %s not found in supposedly synchronized hash",
		    fullName);
	}
	prefixObj = (Tcl_Obj *) Tcl_GetHashValue(hPtr);

	/*
	 * Cache for later in the subcommand object.
	 */
Changes to generic/tclObj.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/* 
 * tclObj.c --
 *
 *	This file contains Tcl object-related procedures that are used by
 * 	many Tcl commands.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 * Copyright (c) 1999 by Scriptics Corporation.
 * Copyright (c) 2001 by ActiveState Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclObj.c,v 1.46.2.4 2003/10/16 02:28:02 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"
#include "tclPort.h"

/*
 * Table of all object types.
 */

static Tcl_HashTable typeTable;
static int typeTableInitialized = 0;    /* 0 means not yet initialized. */
TCL_DECLARE_MUTEX(tableMutex)

/*
 * Head of the list of free Tcl_Obj structs we maintain.
 */

Tcl_Obj *tclFreeObjList = NULL;
|












|











|







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
/*
 * tclObj.c --
 *
 *	This file contains Tcl object-related procedures that are used by
 * 	many Tcl commands.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 * Copyright (c) 1999 by Scriptics Corporation.
 * Copyright (c) 2001 by ActiveState Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclObj.c,v 1.46.2.5 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"
#include "tclPort.h"

/*
 * Table of all object types.
 */

static Tcl_HashTable typeTable;
static int typeTableInitialized = 0;	/* 0 means not yet initialized. */
TCL_DECLARE_MUTEX(tableMutex)

/*
 * Head of the list of free Tcl_Obj structs we maintain.
 */

Tcl_Obj *tclFreeObjList = NULL;
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
 * means of procedures that can be invoked by generic object code. See also
 * tclStringObj.c, tclListObj.c, tclByteCode.c for other type manager
 * implementations.
 */

Tcl_ObjType tclBooleanType = {
    "boolean",				/* name */
    (Tcl_FreeInternalRepProc *) NULL,   /* freeIntRepProc */
    (Tcl_DupInternalRepProc *) NULL,	/* dupIntRepProc */
    UpdateStringOfBoolean,		/* updateStringProc */
    SetBooleanFromAny			/* setFromAnyProc */
};

Tcl_ObjType tclDoubleType = {
    "double",				/* name */
    (Tcl_FreeInternalRepProc *) NULL,   /* freeIntRepProc */
    (Tcl_DupInternalRepProc *) NULL,	/* dupIntRepProc */
    UpdateStringOfDouble,		/* updateStringProc */
    SetDoubleFromAny			/* setFromAnyProc */
};

Tcl_ObjType tclIntType = {
    "int",				/* name */
    (Tcl_FreeInternalRepProc *) NULL,   /* freeIntRepProc */
    (Tcl_DupInternalRepProc *) NULL,	/* dupIntRepProc */
    UpdateStringOfInt,			/* updateStringProc */
    SetIntFromAny			/* setFromAnyProc */
};

Tcl_ObjType tclWideIntType = {
    "wideInt",				/* name */
    (Tcl_FreeInternalRepProc *) NULL,   /* freeIntRepProc */
    (Tcl_DupInternalRepProc *) NULL,	/* dupIntRepProc */
#ifdef TCL_WIDE_INT_IS_LONG
    UpdateStringOfInt,			/* updateStringProc */
#else /* !TCL_WIDE_INT_IS_LONG */
    UpdateStringOfWideInt,		/* updateStringProc */
#endif /* TCL_WIDE_INT_IS_LONG */
    SetWideIntFromAny			/* setFromAnyProc */







|







|







|







|







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
 * means of procedures that can be invoked by generic object code. See also
 * tclStringObj.c, tclListObj.c, tclByteCode.c for other type manager
 * implementations.
 */

Tcl_ObjType tclBooleanType = {
    "boolean",				/* name */
    (Tcl_FreeInternalRepProc *) NULL,	/* freeIntRepProc */
    (Tcl_DupInternalRepProc *) NULL,	/* dupIntRepProc */
    UpdateStringOfBoolean,		/* updateStringProc */
    SetBooleanFromAny			/* setFromAnyProc */
};

Tcl_ObjType tclDoubleType = {
    "double",				/* name */
    (Tcl_FreeInternalRepProc *) NULL,	/* freeIntRepProc */
    (Tcl_DupInternalRepProc *) NULL,	/* dupIntRepProc */
    UpdateStringOfDouble,		/* updateStringProc */
    SetDoubleFromAny			/* setFromAnyProc */
};

Tcl_ObjType tclIntType = {
    "int",				/* name */
    (Tcl_FreeInternalRepProc *) NULL,	/* freeIntRepProc */
    (Tcl_DupInternalRepProc *) NULL,	/* dupIntRepProc */
    UpdateStringOfInt,			/* updateStringProc */
    SetIntFromAny			/* setFromAnyProc */
};

Tcl_ObjType tclWideIntType = {
    "wideInt",				/* name */
    (Tcl_FreeInternalRepProc *) NULL,	/* freeIntRepProc */
    (Tcl_DupInternalRepProc *) NULL,	/* dupIntRepProc */
#ifdef TCL_WIDE_INT_IS_LONG
    UpdateStringOfInt,			/* updateStringProc */
#else /* !TCL_WIDE_INT_IS_LONG */
    UpdateStringOfWideInt,		/* updateStringProc */
#endif /* TCL_WIDE_INT_IS_LONG */
    SetWideIntFromAny			/* setFromAnyProc */
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246

/*
 *-------------------------------------------------------------------------
 *
 * TclInitObjectSubsystem --
 *
 *	This procedure is invoked to perform once-only initialization of
 *	the type table. It also registers the object types defined in 
 *	this file.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Initializes the table of defined object types "typeTable" with
 *	builtin object types defined in this file.  
 *
 *-------------------------------------------------------------------------
 */

void
TclInitObjSubsystem()
{







|







|







224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246

/*
 *-------------------------------------------------------------------------
 *
 * TclInitObjectSubsystem --
 *
 *	This procedure is invoked to perform once-only initialization of
 *	the type table. It also registers the object types defined in
 *	this file.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Initializes the table of defined object types "typeTable" with
 *	builtin object types defined in this file.
 *
 *-------------------------------------------------------------------------
 */

void
TclInitObjSubsystem()
{
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283

#ifdef TCL_COMPILE_STATS
    Tcl_MutexLock(&tclObjMutex);
    tclObjsAlloced = 0;
    tclObjsFreed = 0;
    {
	int i;
	for (i = 0;  i < TCL_MAX_SHARED_OBJ_STATS;  i++) {
	    tclObjsShared[i] = 0;
	}
    }
    Tcl_MutexUnlock(&tclObjMutex);
#endif
}








|







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

#ifdef TCL_COMPILE_STATS
    Tcl_MutexLock(&tclObjMutex);
    tclObjsAlloced = 0;
    tclObjsFreed = 0;
    {
	int i;
	for (i=0 ; i<TCL_MAX_SHARED_OBJ_STATS ; i++) {
	    tclObjsShared[i] = 0;
	}
    }
    Tcl_MutexUnlock(&tclObjMutex);
#endif
}

396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
				 * name of each registered type is appended
				 * as a list element. */
{
    register Tcl_HashEntry *hPtr;
    Tcl_HashSearch search;
    Tcl_ObjType *typePtr;
    int result;
 
    /*
     * This code assumes that types names do not contain embedded NULLs.
     */

    Tcl_MutexLock(&tableMutex);
    for (hPtr = Tcl_FirstHashEntry(&typeTable, &search);
	    hPtr != NULL;  hPtr = Tcl_NextHashEntry(&search)) {







|







396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
				 * name of each registered type is appended
				 * as a list element. */
{
    register Tcl_HashEntry *hPtr;
    Tcl_HashSearch search;
    Tcl_ObjType *typePtr;
    int result;

    /*
     * This code assumes that types names do not contain embedded NULLs.
     */

    Tcl_MutexLock(&tableMutex);
    for (hPtr = Tcl_FirstHashEntry(&typeTable, &search);
	    hPtr != NULL;  hPtr = Tcl_NextHashEntry(&search)) {
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
    objPtr->length = 0;
    objPtr->typePtr = NULL;
# ifdef TCL_THREADS
    /*
     * Add entry to a thread local map used to check if a Tcl_Obj
     * was allocated by the currently executing thread.
     */
    if (!TclInExit())
    {
        Tcl_HashEntry *hPtr;
        Tcl_HashTable *tablePtr;
        int new;
        ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

        if (tsdPtr->objThreadMap == NULL) {
            tsdPtr->objThreadMap = (Tcl_HashTable *)
                    ckalloc(sizeof(Tcl_HashTable));
            Tcl_InitHashTable(tsdPtr->objThreadMap, TCL_ONE_WORD_KEYS);
        }
        tablePtr = tsdPtr->objThreadMap;
        hPtr = Tcl_CreateHashEntry(tablePtr, (char *) objPtr, &new);
        if (!new) {
            panic("expected to create new entry for object map");
        }
        Tcl_SetHashValue(hPtr, NULL);
    }
# endif /* TCL_THREADS */
}
#endif /* TCL_MEM_DEBUG */








|
<







|





|







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
    objPtr->length = 0;
    objPtr->typePtr = NULL;
# ifdef TCL_THREADS
    /*
     * Add entry to a thread local map used to check if a Tcl_Obj
     * was allocated by the currently executing thread.
     */
    if (!TclInExit()) {

        Tcl_HashEntry *hPtr;
        Tcl_HashTable *tablePtr;
        int new;
        ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);

        if (tsdPtr->objThreadMap == NULL) {
            tsdPtr->objThreadMap = (Tcl_HashTable *)
		    ckalloc(sizeof(Tcl_HashTable));
            Tcl_InitHashTable(tsdPtr->objThreadMap, TCL_ONE_WORD_KEYS);
        }
        tablePtr = tsdPtr->objThreadMap;
        hPtr = Tcl_CreateHashEntry(tablePtr, (char *) objPtr, &new);
        if (!new) {
            Tcl_Panic("expected to create new entry for object map");
        }
        Tcl_SetHashValue(hPtr, NULL);
    }
# endif /* TCL_THREADS */
}
#endif /* TCL_MEM_DEBUG */

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
 */

void
TclFreeObj(objPtr)
    register Tcl_Obj *objPtr;	/* The object to be freed. */
{
    register Tcl_ObjType *typePtr = objPtr->typePtr;
    
#ifdef TCL_MEM_DEBUG
    if ((objPtr)->refCount < -1) {
	panic("Reference count for %lx was negative", objPtr);
    }
#endif /* TCL_MEM_DEBUG */

    if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
	typePtr->freeIntRepProc(objPtr);
    }
    Tcl_InvalidateStringRep(objPtr);

    /*
     * If debugging Tcl's memory usage, deallocate the object using ckfree.
     * Otherwise, deallocate it by adding it onto the list of free
     * Tcl_Obj structs we maintain.
     */

#if defined(TCL_MEM_DEBUG) || defined(PURIFY)
    Tcl_MutexLock(&tclObjMutex);
    ckfree((char *) objPtr);
    Tcl_MutexUnlock(&tclObjMutex);
#elif defined(TCL_THREADS) && defined(USE_THREAD_ALLOC) 
    TclThreadFreeObj(objPtr); 
#else 
    Tcl_MutexLock(&tclObjMutex);
    objPtr->internalRep.otherValuePtr = (VOID *) tclFreeObjList;
    tclFreeObjList = objPtr;
    Tcl_MutexUnlock(&tclObjMutex);
#endif /* TCL_MEM_DEBUG */

#ifdef TCL_COMPILE_STATS







|


|


















|
|
|







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
 */

void
TclFreeObj(objPtr)
    register Tcl_Obj *objPtr;	/* The object to be freed. */
{
    register Tcl_ObjType *typePtr = objPtr->typePtr;

#ifdef TCL_MEM_DEBUG
    if ((objPtr)->refCount < -1) {
	Tcl_Panic("Reference count for %lx was negative", objPtr);
    }
#endif /* TCL_MEM_DEBUG */

    if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
	typePtr->freeIntRepProc(objPtr);
    }
    Tcl_InvalidateStringRep(objPtr);

    /*
     * If debugging Tcl's memory usage, deallocate the object using ckfree.
     * Otherwise, deallocate it by adding it onto the list of free
     * Tcl_Obj structs we maintain.
     */

#if defined(TCL_MEM_DEBUG) || defined(PURIFY)
    Tcl_MutexLock(&tclObjMutex);
    ckfree((char *) objPtr);
    Tcl_MutexUnlock(&tclObjMutex);
#elif defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
    TclThreadFreeObj(objPtr);
#else
    Tcl_MutexLock(&tclObjMutex);
    objPtr->internalRep.otherValuePtr = (VOID *) tclFreeObjList;
    tclFreeObjList = objPtr;
    Tcl_MutexUnlock(&tclObjMutex);
#endif /* TCL_MEM_DEBUG */

#ifdef TCL_COMPILE_STATS
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
 *	     otherwise, the duplicate's string rep is set NULL to mark
 *	     it invalid.
 *	  2) If the source object has an internal representation (i.e. its
 *	     typePtr is non-NULL), the new object's internal rep is set to
 *	     a copy; otherwise the new internal rep is marked invalid.
 *
 * Side effects:
 *      What constitutes "copying" the internal representation depends on
 *	the type. For example, if the argument object is a list,
 *	the element objects it points to will not actually be copied but
 *	will be shared with the duplicate list. That is, the ref counts of
 *	the element objects will be incremented.
 *
 *----------------------------------------------------------------------
 */







|







792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
 *	     otherwise, the duplicate's string rep is set NULL to mark
 *	     it invalid.
 *	  2) If the source object has an internal representation (i.e. its
 *	     typePtr is non-NULL), the new object's internal rep is set to
 *	     a copy; otherwise the new internal rep is marked invalid.
 *
 * Side effects:
 *	What constitutes "copying" the internal representation depends on
 *	the type. For example, if the argument object is a list,
 *	the element objects it points to will not actually be copied but
 *	will be shared with the duplicate list. That is, the ref counts of
 *	the element objects will be incremented.
 *
 *----------------------------------------------------------------------
 */
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
    TclNewObj(dupPtr);

    if (objPtr->bytes == NULL) {
	dupPtr->bytes = NULL;
    } else if (objPtr->bytes != tclEmptyStringRep) {
	TclInitStringRep(dupPtr, objPtr->bytes, objPtr->length);
    }
    
    if (typePtr != NULL) {
	if (typePtr->dupIntRepProc == NULL) {
	    dupPtr->internalRep = objPtr->internalRep;
	    dupPtr->typePtr = typePtr;
	} else {
	    (*typePtr->dupIntRepProc)(objPtr, dupPtr);
	}







|







815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
    TclNewObj(dupPtr);

    if (objPtr->bytes == NULL) {
	dupPtr->bytes = NULL;
    } else if (objPtr->bytes != tclEmptyStringRep) {
	TclInitStringRep(dupPtr, objPtr->bytes, objPtr->length);
    }

    if (typePtr != NULL) {
	if (typePtr->dupIntRepProc == NULL) {
	    dupPtr->internalRep = objPtr->internalRep;
	    dupPtr->typePtr = typePtr;
	} else {
	    (*typePtr->dupIntRepProc)(objPtr, dupPtr);
	}
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
				 * should be returned. */
{
    if (objPtr->bytes != NULL) {
	return objPtr->bytes;
    }

    if (objPtr->typePtr->updateStringProc == NULL) {
	panic("UpdateStringProc should not be invoked for type %s",
		objPtr->typePtr->name);
    }
    (*objPtr->typePtr->updateStringProc)(objPtr);
    return objPtr->bytes;
}

/*







|







858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
				 * should be returned. */
{
    if (objPtr->bytes != NULL) {
	return objPtr->bytes;
    }

    if (objPtr->typePtr->updateStringProc == NULL) {
	Tcl_Panic("UpdateStringProc should not be invoked for type %s",
		objPtr->typePtr->name);
    }
    (*objPtr->typePtr->updateStringProc)(objPtr);
    return objPtr->bytes;
}

/*
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
				 * be returned. */
    register int *lengthPtr;	/* If non-NULL, the location where the string
				 * rep's byte array length should * be stored.
				 * If NULL, no length is stored. */
{
    if (objPtr->bytes == NULL) {
	if (objPtr->typePtr->updateStringProc == NULL) {
	    panic("UpdateStringProc should not be invoked for type %s",
		    objPtr->typePtr->name);
	}
	(*objPtr->typePtr->updateStringProc)(objPtr);
    }

    if (lengthPtr != NULL) {
	*lengthPtr = objPtr->length;
    }
    return objPtr->bytes;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_InvalidateStringRep --
 *
 *	This procedure is called to invalidate an object's string
 *	representation. 
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Deallocates the storage for any old string representation, then
 *	sets the string representation NULL to mark it invalid.







|

















|







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
				 * be returned. */
    register int *lengthPtr;	/* If non-NULL, the location where the string
				 * rep's byte array length should * be stored.
				 * If NULL, no length is stored. */
{
    if (objPtr->bytes == NULL) {
	if (objPtr->typePtr->updateStringProc == NULL) {
	    Tcl_Panic("UpdateStringProc should not be invoked for type %s",
		    objPtr->typePtr->name);
	}
	(*objPtr->typePtr->updateStringProc)(objPtr);
    }

    if (lengthPtr != NULL) {
	*lengthPtr = objPtr->length;
    }
    return objPtr->bytes;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_InvalidateStringRep --
 *
 *	This procedure is called to invalidate an object's string
 *	representation.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Deallocates the storage for any old string representation, then
 *	sets the string representation NULL to mark it invalid.
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
Tcl_NewBooleanObj(boolValue)
    register int boolValue;	/* Boolean used to initialize new object. */
{
    register Tcl_Obj *objPtr;

    TclNewObj(objPtr);
    objPtr->bytes = NULL;
    
    objPtr->internalRep.longValue = (boolValue? 1 : 0);
    objPtr->typePtr = &tclBooleanType;
    return objPtr;
}
#endif /* TCL_MEM_DEBUG */

/*







|







984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
Tcl_NewBooleanObj(boolValue)
    register int boolValue;	/* Boolean used to initialize new object. */
{
    register Tcl_Obj *objPtr;

    TclNewObj(objPtr);
    objPtr->bytes = NULL;

    objPtr->internalRep.longValue = (boolValue? 1 : 0);
    objPtr->typePtr = &tclBooleanType;
    return objPtr;
}
#endif /* TCL_MEM_DEBUG */

/*
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
    register Tcl_Obj *objPtr;

    TclDbNewObj(objPtr, file, line);
    objPtr->bytes = NULL;
    
    objPtr->internalRep.longValue = (boolValue? 1 : 0);
    objPtr->typePtr = &tclBooleanType;
    return objPtr;
}

#else /* if not TCL_MEM_DEBUG */








|







1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
    register Tcl_Obj *objPtr;

    TclDbNewObj(objPtr, file, line);
    objPtr->bytes = NULL;

    objPtr->internalRep.longValue = (boolValue? 1 : 0);
    objPtr->typePtr = &tclBooleanType;
    return objPtr;
}

#else /* if not TCL_MEM_DEBUG */

1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
Tcl_SetBooleanObj(objPtr, boolValue)
    register Tcl_Obj *objPtr;	/* Object whose internal rep to init. */
    register int boolValue;	/* Boolean used to set object's value. */
{
    register Tcl_ObjType *oldTypePtr = objPtr->typePtr;

    if (Tcl_IsShared(objPtr)) {
	panic("Tcl_SetBooleanObj called with shared object");
    }
    
    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }
    
    objPtr->internalRep.longValue = (boolValue? 1 : 0);
    objPtr->typePtr = &tclBooleanType;
    Tcl_InvalidateStringRep(objPtr);
}

/*
 *----------------------------------------------------------------------







|

|



|







1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
Tcl_SetBooleanObj(objPtr, boolValue)
    register Tcl_Obj *objPtr;	/* Object whose internal rep to init. */
    register int boolValue;	/* Boolean used to set object's value. */
{
    register Tcl_ObjType *oldTypePtr = objPtr->typePtr;

    if (Tcl_IsShared(objPtr)) {
	Tcl_Panic("Tcl_SetBooleanObj called with shared object");
    }

    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }

    objPtr->internalRep.longValue = (boolValue? 1 : 0);
    objPtr->typePtr = &tclBooleanType;
    Tcl_InvalidateStringRep(objPtr);
}

/*
 *----------------------------------------------------------------------
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
 * Results:
 *	The return value is a standard Tcl object result. If an error occurs
 *	during conversion, an error message is left in the interpreter's
 *	result unless "interp" is NULL.
 *
 * Side effects:
 *	If the object is not already a boolean, the conversion will free
 *	any old internal representation. 
 *
 *----------------------------------------------------------------------
 */

int
Tcl_GetBooleanFromObj(interp, objPtr, boolPtr)
    Tcl_Interp *interp; 	/* Used for error reporting if not NULL. */







|







1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
 * Results:
 *	The return value is a standard Tcl object result. If an error occurs
 *	during conversion, an error message is left in the interpreter's
 *	result unless "interp" is NULL.
 *
 * Side effects:
 *	If the object is not already a boolean, the conversion will free
 *	any old internal representation.
 *
 *----------------------------------------------------------------------
 */

int
Tcl_GetBooleanFromObj(interp, objPtr, boolPtr)
    Tcl_Interp *interp; 	/* Used for error reporting if not NULL. */
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
SetBooleanFromAny(interp, objPtr)
    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr;	/* The object to convert. */
{
    Tcl_ObjType *oldTypePtr = objPtr->typePtr;
    char *string, *end;
    register char c;
    char lowerCase[10];
    int newBool, length;
    register int i;

    /*
     * Get the string representation. Make it up-to-date if necessary.
     */
    
    string = Tcl_GetStringFromObj(objPtr, &length);

    /*
     * Use the obvious shortcuts for numerical values; if objPtr is not
     * of numerical type, parse its string rep.
     */
	
    if (objPtr->typePtr == &tclIntType) {
	newBool = (objPtr->internalRep.longValue != 0);

    } else if (objPtr->typePtr == &tclDoubleType) {
	newBool = (objPtr->internalRep.doubleValue != 0.0);

    } else if (objPtr->typePtr == &tclWideIntType) {
#ifdef TCL_WIDE_INT_IS_LONG
	newBool = (objPtr->internalRep.longValue != 0);
#else /* !TCL_WIDE_INT_IS_LONG */
	newBool = (objPtr->internalRep.wideValue != Tcl_LongAsWide(0));
#endif /* TCL_WIDE_INT_IS_LONG */


    } else {



























	/*
	 * Copy the string converting its characters to lower case.


	 */
	

	for (i = 0;  (i < 9) && (i < length);  i++) {
	    c = string[i];
	    /*
	     * Weed out international characters so we can safely operate
	     * on single bytes.

	     */



	    
	    if (c & 0x80) {
		goto badBoolean;
	    }
	    if (Tcl_UniCharIsUpper(UCHAR(c))) {



		c = (char) Tcl_UniCharToLower(UCHAR(c));

	    }



	    lowerCase[i] = c;


	}



	lowerCase[i] = 0;
	
	/*
	 * Parse the string as a boolean. We use an implementation here that
	 * doesn't report errors in interp if interp is NULL.
	 */

	

	c = lowerCase[0];
	if ((c == '0') && (lowerCase[1] == '\0')) {
	    newBool = 0;


	} else if ((c == '1') && (lowerCase[1] == '\0')) {
	    newBool = 1;
	} else if ((c == 'y') && (strncmp(lowerCase, "yes", (size_t) length) == 0)) {
	    newBool = 1;
	} else if ((c == 'n') && (strncmp(lowerCase, "no", (size_t) length) == 0)) {
	    newBool = 0;
	} else if ((c == 't') && (strncmp(lowerCase, "true", (size_t) length) == 0)) {
	    newBool = 1;




	} else if ((c == 'f') && (strncmp(lowerCase, "false", (size_t) length) == 0)) {
	    newBool = 0;



	} else if ((c == 'o') && (length >= 2)) {
	    if (strncmp(lowerCase, "on", (size_t) length) == 0) {
		newBool = 1;
	    } else if (strncmp(lowerCase, "off", (size_t) length) == 0) {
		newBool = 0;
	    } else {
		goto badBoolean;
	    }


	} else {

	    double dbl;
	    /*
	     * Boolean values can be extracted from ints or doubles.  Note
	     * that we don't use strtoul or strtoull here because we don't
	     * care about what the value is, just whether it is equal to
	     * zero or not.
	     */
#ifdef TCL_WIDE_INT_IS_LONG
	    newBool = strtol(string, &end, 0);
	    if (end != string) {
		/*
		 * Make sure the string has no garbage after the end of
		 * the int.
		 */
		while ((end < (string+length))
		       && isspace(UCHAR(*end))) { /* INTL: ISO only */
		    end++;
		}
		if (end == (string+length)) {
		    newBool = (newBool != 0);
		    goto goodBoolean;
		}
	    }
#else /* !TCL_WIDE_INT_IS_LONG */
	    Tcl_WideInt wide = strtoll(string, &end, 0);
	    if (end != string) {
		/*
		 * Make sure the string has no garbage after the end of
		 * the wide int.
		 */
		while ((end < (string+length))
		       && isspace(UCHAR(*end))) { /* INTL: ISO only */
		    end++;
		}
		if (end == (string+length)) {
		    newBool = (wide != Tcl_LongAsWide(0));
		    goto goodBoolean;
		}
	    }
#endif /* TCL_WIDE_INT_IS_LONG */
	    /*
	     * Still might be a string containing the characters representing an
	     * int or double that wasn't handled above. This would be a string

	     * like "27" or "1.0" that is non-zero and not "1". Such a string
	     * would result in the boolean value true. We try converting to
	     * double. If that succeeds and the resulting double is non-zero, we
	     * have a "true". Note that numbers can't have embedded NULLs.

	     */
	    
	    dbl = strtod(string, &end);
	    if (end == string) {
		goto badBoolean;
	    }
	    
	    /*
	     * Make sure the string has no garbage after the end of the double.

	     */
	    
	    while ((end < (string+length))
		   && isspace(UCHAR(*end))) { /* INTL: ISO only */
		end++;
	    }
	    if (end != (string+length)) {
		goto badBoolean;
	    }
	    newBool = (dbl != 0.0);
	}







|






|






|


>


>






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


>
>

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

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

<
|
|

<
|
>
>
>
>
|

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


|
|
|
|









|















|









|
|
>
|
|
|
|
>

|




|

|
>

|

|







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
SetBooleanFromAny(interp, objPtr)
    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr;	/* The object to convert. */
{
    Tcl_ObjType *oldTypePtr = objPtr->typePtr;
    char *string, *end;
    register char c;
    char lowerCase[8];
    int newBool, length;
    register int i;

    /*
     * Get the string representation. Make it up-to-date if necessary.
     */

    string = Tcl_GetStringFromObj(objPtr, &length);

    /*
     * Use the obvious shortcuts for numerical values; if objPtr is not
     * of numerical type, parse its string rep.
     */

    if (objPtr->typePtr == &tclIntType) {
	newBool = (objPtr->internalRep.longValue != 0);
	goto goodBoolean;
    } else if (objPtr->typePtr == &tclDoubleType) {
	newBool = (objPtr->internalRep.doubleValue != 0.0);
	goto goodBoolean;
    } else if (objPtr->typePtr == &tclWideIntType) {
#ifdef TCL_WIDE_INT_IS_LONG
	newBool = (objPtr->internalRep.longValue != 0);
#else /* !TCL_WIDE_INT_IS_LONG */
	newBool = (objPtr->internalRep.wideValue != Tcl_LongAsWide(0));
#endif /* TCL_WIDE_INT_IS_LONG */
	goto goodBoolean;
    }

    /*
     * Parse the string as a boolean. We use an implementation here
     * that doesn't report errors in interp if interp is NULL.
     *
     * First we define a macro to factor out the to-lower-case code.
     * The len parameter is the maximum number of characters to copy
     * to allow the following comparisons to proceed correctly,
     * including (properly) the trailing \0 character.  This is done
     * in multiple places so the number of copying steps is minimised
     * and only performed when needed.
     */

#define SBFA_TOLOWER(len)					\
	for (i=0 ; i<(len) && i<length ; i++) {			\
	    c = string[i];					\
	    if (c & 0x80) {					\
		goto badBoolean;				\
	    }							\
	    if (Tcl_UniCharIsUpper(UCHAR(c))) {			\
		c = (char) Tcl_UniCharToLower(UCHAR(c));	\
	    }							\
	    lowerCase[i] = c;					\
	}							\
	lowerCase[i] = 0;

    switch (string[0]) {
    case 'y': case 'Y':
	/*
	 * Copy the string converting its characters to lower case.
	 * This also weeds out international characters so we can
	 * safely operate on single bytes.
	 */

	SBFA_TOLOWER(4);


	/*


	 * Checking the 'y' is redundant, but makes the code clearer.
	 */
	if (strncmp(lowerCase, "yes", (size_t) length) == 0) {
	    newBool = 1;
	    goto goodBoolean;
	}

	goto badBoolean;


    case 'n': case 'N':
	SBFA_TOLOWER(3);
	if (strncmp(lowerCase, "no", (size_t) length) == 0) {
	    newBool = 0;
	    goto goodBoolean;
	}
	goto badBoolean;
    case 't': case 'T':
	SBFA_TOLOWER(5);
	if (strncmp(lowerCase, "true", (size_t) length) == 0) {
	    newBool = 1;
	    goto goodBoolean;
	}
	goto badBoolean;
    case 'f': case 'F':
	SBFA_TOLOWER(6);
	if (strncmp(lowerCase, "false", (size_t) length) == 0) {
	    newBool = 0;




	    goto goodBoolean;
	}
	goto badBoolean;
    case 'o': case 'O':
	if (length < 2) {
	    goto badBoolean;
	}
	SBFA_TOLOWER(4);
	if (strncmp(lowerCase, "on", (size_t) length) == 0) {
	    newBool = 1;

	    goto goodBoolean;
	} else if (strncmp(lowerCase, "off", (size_t) length) == 0) {
	    newBool = 0;

	    goto goodBoolean;
	}
	goto badBoolean;
#undef SBFA_TOLOWER
    case '0':
	if (string[1] == '\0') {
	    newBool = 0;
	    goto goodBoolean;
	}
	goto parseNumeric;
    case '1':
	if (string[1] == '\0') {
	    newBool = 1;



	    goto goodBoolean;
	}
	/* deliberate fall-through */
    default:
    parseNumeric:
	{
	    double dbl;
	    /*
	     * Boolean values can be extracted from ints or doubles.
	     * Note that we don't use strtoul or strtoull here because
	     * we don't care about what the value is, just whether it
	     * is equal to zero or not.
	     */
#ifdef TCL_WIDE_INT_IS_LONG
	    newBool = strtol(string, &end, 0);
	    if (end != string) {
		/*
		 * Make sure the string has no garbage after the end of
		 * the int.
		 */
		while ((end < (string+length))
			&& isspace(UCHAR(*end))) { /* INTL: ISO only */
		    end++;
		}
		if (end == (string+length)) {
		    newBool = (newBool != 0);
		    goto goodBoolean;
		}
	    }
#else /* !TCL_WIDE_INT_IS_LONG */
	    Tcl_WideInt wide = strtoll(string, &end, 0);
	    if (end != string) {
		/*
		 * Make sure the string has no garbage after the end of
		 * the wide int.
		 */
		while ((end < (string+length))
			&& isspace(UCHAR(*end))) { /* INTL: ISO only */
		    end++;
		}
		if (end == (string+length)) {
		    newBool = (wide != Tcl_LongAsWide(0));
		    goto goodBoolean;
		}
	    }
#endif /* TCL_WIDE_INT_IS_LONG */
	    /*
	     * Still might be a string containing the characters
	     * representing an int or double that wasn't handled
	     * above. This would be a string like "27" or "1.0" that
	     * is non-zero and not "1". Such a string would result in
	     * the boolean value true. We try converting to double. If
	     * that succeeds and the resulting double is non-zero, we
	     * have a "true".  Note that numbers can't have embedded
	     * NULLs.
	     */

	    dbl = strtod(string, &end);
	    if (end == string) {
		goto badBoolean;
	    }

	    /*
	     * Make sure the string has no garbage after the end of
	     * the double.
	     */

	    while ((end < (string+length))
		    && isspace(UCHAR(*end))) { /* INTL: ISO only */
		end++;
	    }
	    if (end != (string+length)) {
		goto badBoolean;
	    }
	    newBool = (dbl != 0.0);
	}
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
/*
 *----------------------------------------------------------------------
 *
 * UpdateStringOfBoolean --
 *
 *	Update the string representation for a boolean object.
 *	Note: This procedure does not free an existing old string rep
 *	so storage will be lost if this has not already been done. 
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The object's string is set to a valid string that results from
 *	the boolean-to-string conversion.
 *
 *----------------------------------------------------------------------
 */

static void
UpdateStringOfBoolean(objPtr)
    register Tcl_Obj *objPtr;	/* Int object whose string rep to update. */
{
    char *s = ckalloc((unsigned) 2);
    
    s[0] = (char) (objPtr->internalRep.longValue? '1' : '0');
    s[1] = '\0';
    objPtr->bytes = s;
    objPtr->length = 1;
}

/*







|
















|







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
/*
 *----------------------------------------------------------------------
 *
 * UpdateStringOfBoolean --
 *
 *	Update the string representation for a boolean object.
 *	Note: This procedure does not free an existing old string rep
 *	so storage will be lost if this has not already been done.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The object's string is set to a valid string that results from
 *	the boolean-to-string conversion.
 *
 *----------------------------------------------------------------------
 */

static void
UpdateStringOfBoolean(objPtr)
    register Tcl_Obj *objPtr;	/* Int object whose string rep to update. */
{
    char *s = ckalloc((unsigned) 2);

    s[0] = (char) (objPtr->internalRep.longValue? '1' : '0');
    s[1] = '\0';
    objPtr->bytes = s;
    objPtr->length = 1;
}

/*
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
Tcl_NewDoubleObj(dblValue)
    register double dblValue;	/* Double used to initialize the object. */
{
    register Tcl_Obj *objPtr;

    TclNewObj(objPtr);
    objPtr->bytes = NULL;
    
    objPtr->internalRep.doubleValue = dblValue;
    objPtr->typePtr = &tclDoubleType;
    return objPtr;
}
#endif /* if TCL_MEM_DEBUG */

/*







|







1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
Tcl_NewDoubleObj(dblValue)
    register double dblValue;	/* Double used to initialize the object. */
{
    register Tcl_Obj *objPtr;

    TclNewObj(objPtr);
    objPtr->bytes = NULL;

    objPtr->internalRep.doubleValue = dblValue;
    objPtr->typePtr = &tclDoubleType;
    return objPtr;
}
#endif /* if TCL_MEM_DEBUG */

/*
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
    register Tcl_Obj *objPtr;

    TclDbNewObj(objPtr, file, line);
    objPtr->bytes = NULL;
    
    objPtr->internalRep.doubleValue = dblValue;
    objPtr->typePtr = &tclDoubleType;
    return objPtr;
}

#else /* if not TCL_MEM_DEBUG */








|







1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
    register Tcl_Obj *objPtr;

    TclDbNewObj(objPtr, file, line);
    objPtr->bytes = NULL;

    objPtr->internalRep.doubleValue = dblValue;
    objPtr->typePtr = &tclDoubleType;
    return objPtr;
}

#else /* if not TCL_MEM_DEBUG */

1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
Tcl_SetDoubleObj(objPtr, dblValue)
    register Tcl_Obj *objPtr;	/* Object whose internal rep to init. */
    register double dblValue;	/* Double used to set the object's value. */
{
    register Tcl_ObjType *oldTypePtr = objPtr->typePtr;

    if (Tcl_IsShared(objPtr)) {
	panic("Tcl_SetDoubleObj called with shared object");
    }

    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }
    
    objPtr->internalRep.doubleValue = dblValue;
    objPtr->typePtr = &tclDoubleType;
    Tcl_InvalidateStringRep(objPtr);
}

/*
 *----------------------------------------------------------------------







|





|







1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
Tcl_SetDoubleObj(objPtr, dblValue)
    register Tcl_Obj *objPtr;	/* Object whose internal rep to init. */
    register double dblValue;	/* Double used to set the object's value. */
{
    register Tcl_ObjType *oldTypePtr = objPtr->typePtr;

    if (Tcl_IsShared(objPtr)) {
	Tcl_Panic("Tcl_SetDoubleObj called with shared object");
    }

    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }

    objPtr->internalRep.doubleValue = dblValue;
    objPtr->typePtr = &tclDoubleType;
    Tcl_InvalidateStringRep(objPtr);
}

/*
 *----------------------------------------------------------------------
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
int
Tcl_GetDoubleFromObj(interp, objPtr, dblPtr)
    Tcl_Interp *interp; 	/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr;	/* The object from which to get a double. */
    register double *dblPtr;	/* Place to store resulting double. */
{
    register int result;
    
    if (objPtr->typePtr == &tclDoubleType) {
	*dblPtr = objPtr->internalRep.doubleValue;
	return TCL_OK;
    }

    result = SetDoubleFromAny(interp, objPtr);
    if (result == TCL_OK) {







|







1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
int
Tcl_GetDoubleFromObj(interp, objPtr, dblPtr)
    Tcl_Interp *interp; 	/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr;	/* The object from which to get a double. */
    register double *dblPtr;	/* Place to store resulting double. */
{
    register int result;

    if (objPtr->typePtr == &tclDoubleType) {
	*dblPtr = objPtr->internalRep.doubleValue;
	return TCL_OK;
    }

    result = SetDoubleFromAny(interp, objPtr);
    if (result == TCL_OK) {
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
	}
	return TCL_ERROR;
    }

    /*
     * Make sure that the string has no garbage after the end of the double.
     */
    
    while ((end < (string+length))
	    && isspace(UCHAR(*end))) { /* INTL: ISO space. */
	end++;
    }
    if (end != (string+length)) {
	goto badDouble;
    }
    
    /*
     * The conversion to double succeeded. 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.
     */
    
    if ((oldTypePtr != NULL) &&	(oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }

    objPtr->internalRep.doubleValue = newDouble;
    objPtr->typePtr = &tclDoubleType;
    return TCL_OK;







|







|






|







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
	}
	return TCL_ERROR;
    }

    /*
     * Make sure that the string has no garbage after the end of the double.
     */

    while ((end < (string+length))
	    && isspace(UCHAR(*end))) { /* INTL: ISO space. */
	end++;
    }
    if (end != (string+length)) {
	goto badDouble;
    }

    /*
     * The conversion to double succeeded. 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.
     */

    if ((oldTypePtr != NULL) &&	(oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }

    objPtr->internalRep.doubleValue = newDouble;
    objPtr->typePtr = &tclDoubleType;
    return TCL_OK;
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

static void
UpdateStringOfDouble(objPtr)
    register Tcl_Obj *objPtr;	/* Double obj with string rep to update. */
{
    char buffer[TCL_DOUBLE_SPACE];
    register int len;
    
    Tcl_PrintDouble((Tcl_Interp *) NULL, objPtr->internalRep.doubleValue,
	    buffer);
    len = strlen(buffer);
    
    objPtr->bytes = (char *) ckalloc((unsigned) len + 1);
    strcpy(objPtr->bytes, buffer);
    objPtr->length = len;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_NewIntObj --
 *
 *	If a client is compiled with TCL_MEM_DEBUG defined, calls to
 *	Tcl_NewIntObj to create a new integer object end up calling the
 *	debugging procedure Tcl_DbNewLongObj instead.
 *
 *	Otherwise, if the client is compiled without TCL_MEM_DEBUG defined,
 *	calls to Tcl_NewIntObj result in a call to one of the two
 *	Tcl_NewIntObj implementations below. We provide two implementations
 *	so that the Tcl core can be compiled to do memory debugging of the 
 *	core even if a client does not request it for itself.
 *
 *	Integer and long integer objects share the same "integer" type
 *	implementation. We store all integers as longs and Tcl_GetIntFromObj
 *	checks whether the current value of the long can be represented by
 *	an int.
 *







|



|

















|







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

static void
UpdateStringOfDouble(objPtr)
    register Tcl_Obj *objPtr;	/* Double obj with string rep to update. */
{
    char buffer[TCL_DOUBLE_SPACE];
    register int len;

    Tcl_PrintDouble((Tcl_Interp *) NULL, objPtr->internalRep.doubleValue,
	    buffer);
    len = strlen(buffer);

    objPtr->bytes = (char *) ckalloc((unsigned) len + 1);
    strcpy(objPtr->bytes, buffer);
    objPtr->length = len;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_NewIntObj --
 *
 *	If a client is compiled with TCL_MEM_DEBUG defined, calls to
 *	Tcl_NewIntObj to create a new integer object end up calling the
 *	debugging procedure Tcl_DbNewLongObj instead.
 *
 *	Otherwise, if the client is compiled without TCL_MEM_DEBUG defined,
 *	calls to Tcl_NewIntObj result in a call to one of the two
 *	Tcl_NewIntObj implementations below. We provide two implementations
 *	so that the Tcl core can be compiled to do memory debugging of the
 *	core even if a client does not request it for itself.
 *
 *	Integer and long integer objects share the same "integer" type
 *	implementation. We store all integers as longs and Tcl_GetIntFromObj
 *	checks whether the current value of the long can be represented by
 *	an int.
 *
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
Tcl_NewIntObj(intValue)
    register int intValue;	/* Int used to initialize the new object. */
{
    register Tcl_Obj *objPtr;

    TclNewObj(objPtr);
    objPtr->bytes = NULL;
    
    objPtr->internalRep.longValue = (long)intValue;
    objPtr->typePtr = &tclIntType;
    return objPtr;
}
#endif /* if TCL_MEM_DEBUG */

/*
 *----------------------------------------------------------------------
 *
 * Tcl_SetIntObj --
 *
 *	Modify an object to be an integer and to have the specified integer
 *	value.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The object's old string rep, if any, is freed. Also, any old
 *	internal rep is freed. 
 *
 *----------------------------------------------------------------------
 */

void
Tcl_SetIntObj(objPtr, intValue)
    register Tcl_Obj *objPtr;	/* Object whose internal rep to init. */
    register int intValue;	/* Integer used to set object's value. */
{
    register Tcl_ObjType *oldTypePtr = objPtr->typePtr;

    if (Tcl_IsShared(objPtr)) {
	panic("Tcl_SetIntObj called with shared object");
    }
    
    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }
    
    objPtr->internalRep.longValue = (long) intValue;
    objPtr->typePtr = &tclIntType;
    Tcl_InvalidateStringRep(objPtr);
}

/*
 *----------------------------------------------------------------------







|



















|












|

|



|







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
Tcl_NewIntObj(intValue)
    register int intValue;	/* Int used to initialize the new object. */
{
    register Tcl_Obj *objPtr;

    TclNewObj(objPtr);
    objPtr->bytes = NULL;

    objPtr->internalRep.longValue = (long)intValue;
    objPtr->typePtr = &tclIntType;
    return objPtr;
}
#endif /* if TCL_MEM_DEBUG */

/*
 *----------------------------------------------------------------------
 *
 * Tcl_SetIntObj --
 *
 *	Modify an object to be an integer and to have the specified integer
 *	value.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The object's old string rep, if any, is freed. Also, any old
 *	internal rep is freed.
 *
 *----------------------------------------------------------------------
 */

void
Tcl_SetIntObj(objPtr, intValue)
    register Tcl_Obj *objPtr;	/* Object whose internal rep to init. */
    register int intValue;	/* Integer used to set object's value. */
{
    register Tcl_ObjType *oldTypePtr = objPtr->typePtr;

    if (Tcl_IsShared(objPtr)) {
	Tcl_Panic("Tcl_SetIntObj called with shared object");
    }

    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }

    objPtr->internalRep.longValue = (long) intValue;
    objPtr->typePtr = &tclIntType;
    Tcl_InvalidateStringRep(objPtr);
}

/*
 *----------------------------------------------------------------------
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
Tcl_GetIntFromObj(interp, objPtr, intPtr)
    Tcl_Interp *interp; 	/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr;	/* The object from which to get a int. */
    register int *intPtr;	/* Place to store resulting int. */
{
    register long l;
    int result;
    
    if (objPtr->typePtr != &tclIntType) {
	result = SetIntFromAny(interp, objPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }
    l = objPtr->internalRep.longValue;







|







1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
Tcl_GetIntFromObj(interp, objPtr, intPtr)
    Tcl_Interp *interp; 	/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr;	/* The object from which to get a int. */
    register int *intPtr;	/* Place to store resulting int. */
{
    register long l;
    int result;

    if (objPtr->typePtr != &tclIntType) {
	result = SetIntFromAny(interp, objPtr);
	if (result != TCL_OK) {
	    return result;
	}
    }
    l = objPtr->internalRep.longValue;
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
 * Results:
 *	The return value is a standard object Tcl result. If an error occurs
 *	during conversion, an error message is left in the interpreter's
 *	result unless "interp" is NULL.
 *
 * Side effects:
 *	If no error occurs, an int is stored as "objPtr"s internal
 *	representation. 
 *
 *----------------------------------------------------------------------
 */

static int
SetIntFromAny(interp, objPtr)
    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */







|







1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
 * Results:
 *	The return value is a standard object Tcl result. If an error occurs
 *	during conversion, an error message is left in the interpreter's
 *	result unless "interp" is NULL.
 *
 * Side effects:
 *	If no error occurs, an int is stored as "objPtr"s internal
 *	representation.
 *
 *----------------------------------------------------------------------
 */

static int
SetIntFromAny(interp, objPtr)
    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
     * strtoul instead of strtol for integer conversions to allow full-size
     * unsigned numbers, but don't depend on strtoul to handle sign
     * characters; it won't in some implementations.
     */

    errno = 0;
#ifdef TCL_STRTOUL_SIGN_CHECK
    for ( ;  isspace(UCHAR(*p));  p++) { /* INTL: ISO space. */
	/* Empty loop body. */
    }
    if (*p == '-') {
	p++;
	newLong = -((long)strtoul(p, &end, 0));
    } else if (*p == '+') {
	p++;







|







1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
     * strtoul instead of strtol for integer conversions to allow full-size
     * unsigned numbers, but don't depend on strtoul to handle sign
     * characters; it won't in some implementations.
     */

    errno = 0;
#ifdef TCL_STRTOUL_SIGN_CHECK
    for (; isspace(UCHAR(*p)) ; p++) {	/* INTL: ISO space. */
	/* Empty loop body. */
    }
    if (*p == '-') {
	p++;
	newLong = -((long)strtoul(p, &end, 0));
    } else if (*p == '+') {
	p++;
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
	}
	return TCL_ERROR;
    }

    /*
     * Make sure that the string has no garbage after the end of the int.
     */
    
    while ((end < (string+length))
	    && isspace(UCHAR(*end))) { /* INTL: ISO space. */
	end++;
    }
    if (end != (string+length)) {
	goto badInteger;
    }







|







1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
	}
	return TCL_ERROR;
    }

    /*
     * Make sure that the string has no garbage after the end of the int.
     */

    while ((end < (string+length))
	    && isspace(UCHAR(*end))) { /* INTL: ISO space. */
	end++;
    }
    if (end != (string+length)) {
	goto badInteger;
    }
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
/*
 *----------------------------------------------------------------------
 *
 * UpdateStringOfInt --
 *
 *	Update the string representation for an integer object.
 *	Note: This procedure does not free an existing old string rep
 *	so storage will be lost if this has not already been done. 
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The object's string is set to a valid string that results from
 *	the int-to-string conversion.
 *
 *----------------------------------------------------------------------
 */

static void
UpdateStringOfInt(objPtr)
    register Tcl_Obj *objPtr;	/* Int object whose string rep to update. */
{
    char buffer[TCL_INTEGER_SPACE];
    register int len;
    
    len = TclFormatInt(buffer, objPtr->internalRep.longValue);
    
    objPtr->bytes = ckalloc((unsigned) len + 1);
    strcpy(objPtr->bytes, buffer);
    objPtr->length = len;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_NewLongObj --
 *
 *	If a client is compiled with TCL_MEM_DEBUG defined, calls to
 *	Tcl_NewLongObj to create a new long integer object end up calling
 *	the debugging procedure Tcl_DbNewLongObj instead.
 *
 *	Otherwise, if the client is compiled without TCL_MEM_DEBUG defined,
 *	calls to Tcl_NewLongObj result in a call to one of the two
 *	Tcl_NewLongObj implementations below. We provide two implementations
 *	so that the Tcl core can be compiled to do memory debugging of the 
 *	core even if a client does not request it for itself.
 *
 *	Integer and long integer objects share the same "integer" type
 *	implementation. We store all integers as longs and Tcl_GetIntFromObj
 *	checks whether the current value of the long can be represented by
 *	an int.
 *







|

















|

|

















|







1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
/*
 *----------------------------------------------------------------------
 *
 * UpdateStringOfInt --
 *
 *	Update the string representation for an integer object.
 *	Note: This procedure does not free an existing old string rep
 *	so storage will be lost if this has not already been done.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The object's string is set to a valid string that results from
 *	the int-to-string conversion.
 *
 *----------------------------------------------------------------------
 */

static void
UpdateStringOfInt(objPtr)
    register Tcl_Obj *objPtr;	/* Int object whose string rep to update. */
{
    char buffer[TCL_INTEGER_SPACE];
    register int len;

    len = TclFormatInt(buffer, objPtr->internalRep.longValue);

    objPtr->bytes = ckalloc((unsigned) len + 1);
    strcpy(objPtr->bytes, buffer);
    objPtr->length = len;
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_NewLongObj --
 *
 *	If a client is compiled with TCL_MEM_DEBUG defined, calls to
 *	Tcl_NewLongObj to create a new long integer object end up calling
 *	the debugging procedure Tcl_DbNewLongObj instead.
 *
 *	Otherwise, if the client is compiled without TCL_MEM_DEBUG defined,
 *	calls to Tcl_NewLongObj result in a call to one of the two
 *	Tcl_NewLongObj implementations below. We provide two implementations
 *	so that the Tcl core can be compiled to do memory debugging of the
 *	core even if a client does not request it for itself.
 *
 *	Integer and long integer objects share the same "integer" type
 *	implementation. We store all integers as longs and Tcl_GetIntFromObj
 *	checks whether the current value of the long can be represented by
 *	an int.
 *
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
    register long longValue;	/* Long integer used to initialize the
				 * new object. */
{
    register Tcl_Obj *objPtr;

    TclNewObj(objPtr);
    objPtr->bytes = NULL;
    
    objPtr->internalRep.longValue = longValue;
    objPtr->typePtr = &tclIntType;
    return objPtr;
}
#endif /* if TCL_MEM_DEBUG */

/*







|







2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
    register long longValue;	/* Long integer used to initialize the
				 * new object. */
{
    register Tcl_Obj *objPtr;

    TclNewObj(objPtr);
    objPtr->bytes = NULL;

    objPtr->internalRep.longValue = longValue;
    objPtr->typePtr = &tclIntType;
    return objPtr;
}
#endif /* if TCL_MEM_DEBUG */

/*
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
    register Tcl_Obj *objPtr;

    TclDbNewObj(objPtr, file, line);
    objPtr->bytes = NULL;
    
    objPtr->internalRep.longValue = longValue;
    objPtr->typePtr = &tclIntType;
    return objPtr;
}

#else /* if not TCL_MEM_DEBUG */








|







2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
    register Tcl_Obj *objPtr;

    TclDbNewObj(objPtr, file, line);
    objPtr->bytes = NULL;

    objPtr->internalRep.longValue = longValue;
    objPtr->typePtr = &tclIntType;
    return objPtr;
}

#else /* if not TCL_MEM_DEBUG */

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
 *	long integer value.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The object's old string rep, if any, is freed. Also, any old
 *	internal rep is freed. 
 *
 *----------------------------------------------------------------------
 */

void
Tcl_SetLongObj(objPtr, longValue)
    register Tcl_Obj *objPtr;	/* Object whose internal rep to init. */
    register long longValue;	/* Long integer used to initialize the
				 * object's value. */
{
    register Tcl_ObjType *oldTypePtr = objPtr->typePtr;

    if (Tcl_IsShared(objPtr)) {
	panic("Tcl_SetLongObj called with shared object");
    }

    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }
    
    objPtr->internalRep.longValue = longValue;
    objPtr->typePtr = &tclIntType;
    Tcl_InvalidateStringRep(objPtr);
}

/*
 *----------------------------------------------------------------------







|













|





|







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
 *	long integer value.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The object's old string rep, if any, is freed. Also, any old
 *	internal rep is freed.
 *
 *----------------------------------------------------------------------
 */

void
Tcl_SetLongObj(objPtr, longValue)
    register Tcl_Obj *objPtr;	/* Object whose internal rep to init. */
    register long longValue;	/* Long integer used to initialize the
				 * object's value. */
{
    register Tcl_ObjType *oldTypePtr = objPtr->typePtr;

    if (Tcl_IsShared(objPtr)) {
	Tcl_Panic("Tcl_SetLongObj called with shared object");
    }

    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }

    objPtr->internalRep.longValue = longValue;
    objPtr->typePtr = &tclIntType;
    Tcl_InvalidateStringRep(objPtr);
}

/*
 *----------------------------------------------------------------------
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
int
Tcl_GetLongFromObj(interp, objPtr, longPtr)
    Tcl_Interp *interp; 	/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr;	/* The object from which to get a long. */
    register long *longPtr;	/* Place to store resulting long. */
{
    register int result;
    
    if (objPtr->typePtr == &tclIntType) {
	*longPtr = objPtr->internalRep.longValue;
	return TCL_OK;
    }
    result = SetIntFromAny(interp, objPtr);
    if (result == TCL_OK) {
	*longPtr = objPtr->internalRep.longValue;







|







2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
int
Tcl_GetLongFromObj(interp, objPtr, longPtr)
    Tcl_Interp *interp; 	/* Used for error reporting if not NULL. */
    register Tcl_Obj *objPtr;	/* The object from which to get a long. */
    register long *longPtr;	/* Place to store resulting long. */
{
    register int result;

    if (objPtr->typePtr == &tclIntType) {
	*longPtr = objPtr->internalRep.longValue;
	return TCL_OK;
    }
    result = SetIntFromAny(interp, objPtr);
    if (result == TCL_OK) {
	*longPtr = objPtr->internalRep.longValue;
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
 * Results:
 *	The return value is a standard object Tcl result. If an error occurs
 *	during conversion, an error message is left in the interpreter's
 *	result unless "interp" is NULL.
 *
 * Side effects:
 *	If no error occurs, an int is stored as "objPtr"s internal
 *	representation. 
 *
 *----------------------------------------------------------------------
 */

static int
SetWideIntFromAny(interp, objPtr)
    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */







|







2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
 * Results:
 *	The return value is a standard object Tcl result. If an error occurs
 *	during conversion, an error message is left in the interpreter's
 *	result unless "interp" is NULL.
 *
 * Side effects:
 *	If no error occurs, an int is stored as "objPtr"s internal
 *	representation.
 *
 *----------------------------------------------------------------------
 */

static int
SetWideIntFromAny(interp, objPtr)
    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
     * strtoull instead of strtoll for integer conversions to allow full-size
     * unsigned numbers, but don't depend on strtoull to handle sign
     * characters; it won't in some implementations.
     */

    errno = 0;
#ifdef TCL_STRTOUL_SIGN_CHECK
    for ( ;  isspace(UCHAR(*p));  p++) { /* INTL: ISO space. */
	/* Empty loop body. */
    }
    if (*p == '-') {
	p++;
	newWide = -((Tcl_WideInt)strtoull(p, &end, 0));
    } else if (*p == '+') {
	p++;







|







2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
     * strtoull instead of strtoll for integer conversions to allow full-size
     * unsigned numbers, but don't depend on strtoull to handle sign
     * characters; it won't in some implementations.
     */

    errno = 0;
#ifdef TCL_STRTOUL_SIGN_CHECK
    for (; isspace(UCHAR(*p)) ; p++) {	/* INTL: ISO space. */
	/* Empty loop body. */
    }
    if (*p == '-') {
	p++;
	newWide = -((Tcl_WideInt)strtoull(p, &end, 0));
    } else if (*p == '+') {
	p++;
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
	}
	return TCL_ERROR;
    }

    /*
     * Make sure that the string has no garbage after the end of the int.
     */
    
    while ((end < (string+length))
	    && isspace(UCHAR(*end))) { /* INTL: ISO space. */
	end++;
    }
    if (end != (string+length)) {
	goto badInteger;
    }

    /*
     * The conversion to int succeeded. 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.
     */

    if ((oldTypePtr != NULL) &&	(oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }
    
    objPtr->internalRep.wideValue = newWide;
#else 
    if (TCL_ERROR == SetIntFromAny(interp, objPtr)) {
	return TCL_ERROR;
    }
#endif
    objPtr->typePtr = &tclWideIntType;
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * UpdateStringOfWideInt --
 *
 *	Update the string representation for a wide integer object.
 *	Note: This procedure does not free an existing old string rep
 *	so storage will be lost if this has not already been done. 
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The object's string is set to a valid string that results from
 *	the wideInt-to-string conversion.







|


















|

|















|







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
	}
	return TCL_ERROR;
    }

    /*
     * Make sure that the string has no garbage after the end of the int.
     */

    while ((end < (string+length))
	    && isspace(UCHAR(*end))) { /* INTL: ISO space. */
	end++;
    }
    if (end != (string+length)) {
	goto badInteger;
    }

    /*
     * The conversion to int succeeded. 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.
     */

    if ((oldTypePtr != NULL) &&	(oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }

    objPtr->internalRep.wideValue = newWide;
#else
    if (TCL_ERROR == SetIntFromAny(interp, objPtr)) {
	return TCL_ERROR;
    }
#endif
    objPtr->typePtr = &tclWideIntType;
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * UpdateStringOfWideInt --
 *
 *	Update the string representation for a wide integer object.
 *	Note: This procedure does not free an existing old string rep
 *	so storage will be lost if this has not already been done.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The object's string is set to a valid string that results from
 *	the wideInt-to-string conversion.
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
 *	If a client is compiled with TCL_MEM_DEBUG defined, calls to
 *	Tcl_NewWideIntObj to create a new 64-bit integer object end up calling
 *	the debugging procedure Tcl_DbNewWideIntObj instead.
 *
 *	Otherwise, if the client is compiled without TCL_MEM_DEBUG defined,
 *	calls to Tcl_NewWideIntObj result in a call to one of the two
 *	Tcl_NewWideIntObj implementations below. We provide two implementations
 *	so that the Tcl core can be compiled to do memory debugging of the 
 *	core even if a client does not request it for itself.
 *
 * Results:
 *	The newly created object is returned. This object will have an
 *	invalid string representation. The returned object has ref count 0.
 *
 * Side effects:







|







2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
 *	If a client is compiled with TCL_MEM_DEBUG defined, calls to
 *	Tcl_NewWideIntObj to create a new 64-bit integer object end up calling
 *	the debugging procedure Tcl_DbNewWideIntObj instead.
 *
 *	Otherwise, if the client is compiled without TCL_MEM_DEBUG defined,
 *	calls to Tcl_NewWideIntObj result in a call to one of the two
 *	Tcl_NewWideIntObj implementations below. We provide two implementations
 *	so that the Tcl core can be compiled to do memory debugging of the
 *	core even if a client does not request it for itself.
 *
 * Results:
 *	The newly created object is returned. This object will have an
 *	invalid string representation. The returned object has ref count 0.
 *
 * Side effects:
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
    register Tcl_WideInt wideValue;	/* Wide integer used to initialize
					 * the new object. */
{
    register Tcl_Obj *objPtr;

    TclNewObj(objPtr);
    objPtr->bytes = NULL;
    
    objPtr->internalRep.wideValue = wideValue;
    objPtr->typePtr = &tclWideIntType;
    return objPtr;
}
#endif /* if TCL_MEM_DEBUG */

/*







|







2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
    register Tcl_WideInt wideValue;	/* Wide integer used to initialize
					 * the new object. */
{
    register Tcl_Obj *objPtr;

    TclNewObj(objPtr);
    objPtr->bytes = NULL;

    objPtr->internalRep.wideValue = wideValue;
    objPtr->typePtr = &tclWideIntType;
    return objPtr;
}
#endif /* if TCL_MEM_DEBUG */

/*
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
    int line;				/* Line number in the source file;
					 * used for debugging. */
{
    register Tcl_Obj *objPtr;

    TclDbNewObj(objPtr, file, line);
    objPtr->bytes = NULL;
    
    objPtr->internalRep.wideValue = wideValue;
    objPtr->typePtr = &tclWideIntType;
    return objPtr;
}

#else /* if not TCL_MEM_DEBUG */








|







2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
    int line;				/* Line number in the source file;
					 * used for debugging. */
{
    register Tcl_Obj *objPtr;

    TclDbNewObj(objPtr, file, line);
    objPtr->bytes = NULL;

    objPtr->internalRep.wideValue = wideValue;
    objPtr->typePtr = &tclWideIntType;
    return objPtr;
}

#else /* if not TCL_MEM_DEBUG */

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
 *	specified wide integer value.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The object's old string rep, if any, is freed. Also, any old
 *	internal rep is freed. 
 *
 *----------------------------------------------------------------------
 */

void
Tcl_SetWideIntObj(objPtr, wideValue)
    register Tcl_Obj *objPtr;		/* Object w. internal rep to init. */
    register Tcl_WideInt wideValue;	/* Wide integer used to initialize
					 * the object's value. */
{
    register Tcl_ObjType *oldTypePtr = objPtr->typePtr;

    if (Tcl_IsShared(objPtr)) {
	panic("Tcl_SetWideIntObj called with shared object");
    }

    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }
    
    objPtr->internalRep.wideValue = wideValue;
    objPtr->typePtr = &tclWideIntType;
    Tcl_InvalidateStringRep(objPtr);
}

/*
 *----------------------------------------------------------------------







|













|





|







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
 *	specified wide integer value.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The object's old string rep, if any, is freed. Also, any old
 *	internal rep is freed.
 *
 *----------------------------------------------------------------------
 */

void
Tcl_SetWideIntObj(objPtr, wideValue)
    register Tcl_Obj *objPtr;		/* Object w. internal rep to init. */
    register Tcl_WideInt wideValue;	/* Wide integer used to initialize
					 * the object's value. */
{
    register Tcl_ObjType *oldTypePtr = objPtr->typePtr;

    if (Tcl_IsShared(objPtr)) {
	Tcl_Panic("Tcl_SetWideIntObj called with shared object");
    }

    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }

    objPtr->internalRep.wideValue = wideValue;
    objPtr->typePtr = &tclWideIntType;
    Tcl_InvalidateStringRep(objPtr);
}

/*
 *----------------------------------------------------------------------
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
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
#ifdef TCL_MEM_DEBUG
    if (objPtr->refCount == 0x61616161) {
	fprintf(stderr, "file = %s, line = %d\n", file, line);
	fflush(stderr);
	panic("Trying to increment refCount of previously disposed object.");
    }
# ifdef TCL_THREADS
    /*
     * 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) {
            panic("object table not initialized");
        }
        hPtr = Tcl_FindHashEntry(tablePtr, (char *) objPtr);
        if (!hPtr) {
            panic("%s%s",
                    "Trying to incr ref count of",
                    "Tcl_Obj allocated in another thread");
        }
    }
# endif
#endif
    ++(objPtr)->refCount;







|















|



|







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
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
#ifdef TCL_MEM_DEBUG
    if (objPtr->refCount == 0x61616161) {
	fprintf(stderr, "file = %s, line = %d\n", file, line);
	fflush(stderr);
	Tcl_Panic("Trying to increment refCount of previously disposed object.");
    }
# ifdef TCL_THREADS
    /*
     * 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, (char *) objPtr);
        if (!hPtr) {
            Tcl_Panic("%s%s",
                    "Trying to incr ref count of",
                    "Tcl_Obj allocated in another thread");
        }
    }
# endif
#endif
    ++(objPtr)->refCount;
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
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
#ifdef TCL_MEM_DEBUG
    if (objPtr->refCount == 0x61616161) {
	fprintf(stderr, "file = %s, line = %d\n", file, line);
	fflush(stderr);
	panic("Trying to decrement refCount of previously disposed object.");
    }
# ifdef TCL_THREADS
    /*
     * 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) {
            panic("object table not initialized");
        }
        hPtr = Tcl_FindHashEntry(tablePtr, (char *) objPtr);
        if (!hPtr) {
            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) {
            Tcl_DeleteHashEntry(hPtr);







|















|



|







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
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
#ifdef TCL_MEM_DEBUG
    if (objPtr->refCount == 0x61616161) {
	fprintf(stderr, "file = %s, line = %d\n", file, line);
	fflush(stderr);
	Tcl_Panic("Trying to decrement refCount of previously disposed object.");
    }
# ifdef TCL_THREADS
    /*
     * 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, (char *) 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) {
            Tcl_DeleteHashEntry(hPtr);
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
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
#ifdef TCL_MEM_DEBUG
    if (objPtr->refCount == 0x61616161) {
	fprintf(stderr, "file = %s, line = %d\n", file, line);
	fflush(stderr);
	panic("Trying to check whether previously disposed object is shared.");
    }
# ifdef TCL_THREADS
    /*
     * 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) {
            panic("object table not initialized");
        }
        hPtr = Tcl_FindHashEntry(tablePtr, (char *) objPtr);
        if (!hPtr) {
            panic("%s%s",
                    "Trying to check shared status of",
                    "Tcl_Obj allocated in another thread");
        }
    }
# endif
#endif
#ifdef TCL_COMPILE_STATS







|















|



|







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
    int line;			/* Line number in the source file; used
				 * for debugging. */
{
#ifdef TCL_MEM_DEBUG
    if (objPtr->refCount == 0x61616161) {
	fprintf(stderr, "file = %s, line = %d\n", file, line);
	fflush(stderr);
	Tcl_Panic("Trying to check whether previously disposed object is shared.");
    }
# ifdef TCL_THREADS
    /*
     * 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, (char *) 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
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
     * Don't use Tcl_GetStringFromObj as it would prevent l1 and l2 being
     * in a register.
     */
    p1 = Tcl_GetString (objPtr1);
    l1 = objPtr1->length;
    p2 = Tcl_GetString (objPtr2);
    l2 = objPtr2->length;
    
    /*
     * Only compare if the string representations are of the same length.
     */
    if (l1 == l2) {
	for (;; p1++, p2++, l1--) {
	    if (*p1 != *p2) {
		break;







|







2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
     * Don't use Tcl_GetStringFromObj as it would prevent l1 and l2 being
     * in a register.
     */
    p1 = Tcl_GetString (objPtr1);
    l1 = objPtr1->length;
    p2 = Tcl_GetString (objPtr2);
    l2 = objPtr2->length;

    /*
     * Only compare if the string representations are of the same length.
     */
    if (l1 == l2) {
	for (;; p1++, p2++, l1--) {
	    if (*p1 != *p2) {
		break;
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
    register CONST char *string;
    register int length;
    register unsigned int result;
    register int c;

    string = Tcl_GetString (objPtr);
    length = objPtr->length;
    
    /*
     * I tried a zillion different hash functions and asked many other
     * people for advice.  Many people had their own favorite functions,
     * all different, but no-one had much idea why they were good ones.
     * I chose the one below (multiply by 9 and add new character)
     * because of the following reasons:
     *







|







2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
    register CONST char *string;
    register int length;
    register unsigned int result;
    register int c;

    string = Tcl_GetString (objPtr);
    length = objPtr->length;

    /*
     * I tried a zillion different hash functions and asked many other
     * people for advice.  Many people had their own favorite functions,
     * all different, but no-one had much idea why they were good ones.
     * I chose the one below (multiply by 9 and add new character)
     * because of the following reasons:
     *
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_GetCommandFromObj --
 *
 *      Returns the command specified by the name in a Tcl_Obj.
 *
 * Results:
 *	Returns a token for the command if it is found. Otherwise, if it
 *	can't be found or there is an error, returns NULL.
 *
 * Side effects:
 *      May update the internal representation for the object, caching
 *      the command reference so that the next time this procedure is
 *	called with the same object, the command can be found quickly.
 *
 *----------------------------------------------------------------------
 */

Tcl_Command
Tcl_GetCommandFromObj(interp, objPtr)







|






|
|







3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_GetCommandFromObj --
 *
 *	Returns the command specified by the name in a Tcl_Obj.
 *
 * Results:
 *	Returns a token for the command if it is found. Otherwise, if it
 *	can't be found or there is an error, returns NULL.
 *
 * Side effects:
 *	May update the internal representation for the object, caching
 *	the command reference so that the next time this procedure is
 *	called with the same object, the command can be found quickly.
 *
 *----------------------------------------------------------------------
 */

Tcl_Command
Tcl_GetCommandFromObj(interp, objPtr)
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
    Namespace *currNsPtr;
    int result;
    CallFrame *savedFramePtr;
    char *name;

    /*
     * If the variable name is fully qualified, do as if the lookup were
     * done from the global namespace; this helps avoid repeated lookups 
     * of fully qualified names. It costs close to nothing, and may be very
     * helpful for OO applications which pass along a command name ("this"),
     * [Patch 456668]
     */

    savedFramePtr = iPtr->varFramePtr;
    name = Tcl_GetString(objPtr);
    if ((*name++ == ':') && (*name == ':')) {
	iPtr->varFramePtr = NULL;
    }

    /*
     * Get the internal representation, converting to a command type if
     * needed. The internal representation is a ResolvedCmdName that points
     * to the actual command.
     */
    
    if (objPtr->typePtr != &tclCmdNameType) {
        result = tclCmdNameType.setFromAnyProc(interp, objPtr);
        if (result != TCL_OK) {
	    iPtr->varFramePtr = savedFramePtr;
            return (Tcl_Command) NULL;
        }
    }
    resPtr = (ResolvedCmdName *) objPtr->internalRep.twoPtrValue.ptr1;

    /*
     * Get the current namespace.
     */
    
    if (iPtr->varFramePtr != NULL) {
	currNsPtr = iPtr->varFramePtr->nsPtr;
    } else {
	currNsPtr = iPtr->globalNsPtr;
    }

    /*
     * Check the context namespace and the namespace epoch of the resolved
     * symbol to make sure that it is fresh. If not, then force another
     * conversion to the command type, to discard the old rep and create a
     * new one. Note that we verify that the namespace id of the context
     * namespace is the same as the one we cached; this insures that the
     * namespace wasn't deleted and a new one created at the same address
     * with the same command epoch.
     */
    
    cmdPtr = NULL;
    if ((resPtr != NULL)
	    && (resPtr->refNsPtr == currNsPtr)
	    && (resPtr->refNsId == currNsPtr->nsId)
	    && (resPtr->refNsCmdEpoch == currNsPtr->cmdRefEpoch)) {
        cmdPtr = resPtr->cmdPtr;
        if (cmdPtr->cmdEpoch != resPtr->cmdEpoch) {







|
















|












|















|







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
    Namespace *currNsPtr;
    int result;
    CallFrame *savedFramePtr;
    char *name;

    /*
     * If the variable name is fully qualified, do as if the lookup were
     * done from the global namespace; this helps avoid repeated lookups
     * of fully qualified names. It costs close to nothing, and may be very
     * helpful for OO applications which pass along a command name ("this"),
     * [Patch 456668]
     */

    savedFramePtr = iPtr->varFramePtr;
    name = Tcl_GetString(objPtr);
    if ((*name++ == ':') && (*name == ':')) {
	iPtr->varFramePtr = NULL;
    }

    /*
     * Get the internal representation, converting to a command type if
     * needed. The internal representation is a ResolvedCmdName that points
     * to the actual command.
     */

    if (objPtr->typePtr != &tclCmdNameType) {
        result = tclCmdNameType.setFromAnyProc(interp, objPtr);
        if (result != TCL_OK) {
	    iPtr->varFramePtr = savedFramePtr;
            return (Tcl_Command) NULL;
        }
    }
    resPtr = (ResolvedCmdName *) objPtr->internalRep.twoPtrValue.ptr1;

    /*
     * Get the current namespace.
     */

    if (iPtr->varFramePtr != NULL) {
	currNsPtr = iPtr->varFramePtr->nsPtr;
    } else {
	currNsPtr = iPtr->globalNsPtr;
    }

    /*
     * Check the context namespace and the namespace epoch of the resolved
     * symbol to make sure that it is fresh. If not, then force another
     * conversion to the command type, to discard the old rep and create a
     * new one. Note that we verify that the namespace id of the context
     * namespace is the same as the one we cached; this insures that the
     * namespace wasn't deleted and a new one created at the same address
     * with the same command epoch.
     */

    cmdPtr = NULL;
    if ((resPtr != NULL)
	    && (resPtr->refNsPtr == currNsPtr)
	    && (resPtr->refNsId == currNsPtr->nsId)
	    && (resPtr->refNsCmdEpoch == currNsPtr->cmdRefEpoch)) {
        cmdPtr = resPtr->cmdPtr;
        if (cmdPtr->cmdEpoch != resPtr->cmdEpoch) {
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
    register ResolvedCmdName *resPtr;
    Tcl_ObjType *oldTypePtr = objPtr->typePtr;
    register Namespace *currNsPtr;

    if (oldTypePtr == &tclCmdNameType) {
	return;
    }
    
    /*
     * Get the current namespace.
     */
    
    if (iPtr->varFramePtr != NULL) {
	currNsPtr = iPtr->varFramePtr->nsPtr;
    } else {
	currNsPtr = iPtr->globalNsPtr;
    }
    
    cmdPtr->refCount++;
    resPtr = (ResolvedCmdName *) ckalloc(sizeof(ResolvedCmdName));
    resPtr->cmdPtr = cmdPtr;
    resPtr->refNsPtr = currNsPtr;
    resPtr->refNsId  = currNsPtr->nsId;
    resPtr->refNsCmdEpoch = currNsPtr->cmdRefEpoch;
    resPtr->cmdEpoch = cmdPtr->cmdEpoch;
    resPtr->refCount = 1;
    
    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }
    objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) resPtr;
    objPtr->internalRep.twoPtrValue.ptr2 = NULL;
    objPtr->typePtr = &tclCmdNameType;
}







|



|





|




|



|







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
    register ResolvedCmdName *resPtr;
    Tcl_ObjType *oldTypePtr = objPtr->typePtr;
    register Namespace *currNsPtr;

    if (oldTypePtr == &tclCmdNameType) {
	return;
    }

    /*
     * Get the current namespace.
     */

    if (iPtr->varFramePtr != NULL) {
	currNsPtr = iPtr->varFramePtr->nsPtr;
    } else {
	currNsPtr = iPtr->globalNsPtr;
    }

    cmdPtr->refCount++;
    resPtr = (ResolvedCmdName *) ckalloc(sizeof(ResolvedCmdName));
    resPtr->cmdPtr = cmdPtr;
    resPtr->refNsPtr = currNsPtr;
    resPtr->refNsId = currNsPtr->nsId;
    resPtr->refNsCmdEpoch = currNsPtr->cmdRefEpoch;
    resPtr->cmdEpoch = cmdPtr->cmdEpoch;
    resPtr->refCount = 1;

    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
	oldTypePtr->freeIntRepProc(objPtr);
    }
    objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) resPtr;
    objPtr->internalRep.twoPtrValue.ptr2 = NULL;
    objPtr->typePtr = &tclCmdNameType;
}
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
 *	representation.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Decrements the ref count of any cached ResolvedCmdName structure
 *	pointed to by the cmdName's internal representation. If this is 
 *	the last use of the ResolvedCmdName, it is freed. This in turn
 *	decrements the ref count of the Command structure pointed to by 
 *	the ResolvedSymbol, which may free the Command structure.
 *
 *----------------------------------------------------------------------
 */

static void
FreeCmdNameInternalRep(objPtr)
    register Tcl_Obj *objPtr;	/* CmdName object with internal
				 * representation to free. */
{
    register ResolvedCmdName *resPtr =
	(ResolvedCmdName *) objPtr->internalRep.twoPtrValue.ptr1;

    if (resPtr != NULL) {
	/*
	 * Decrement the reference count of the ResolvedCmdName structure.
	 * If there are no more uses, free the ResolvedCmdName structure.
	 */
    
        resPtr->refCount--;
        if (resPtr->refCount == 0) {
            /*
	     * Now free the cached command, unless it is still in its
             * hash table or if there are other references to it
             * from other cmdName objects.
	     */
	    
            Command *cmdPtr = resPtr->cmdPtr;
            TclCleanupCommand(cmdPtr);
            ckfree((char *) resPtr);
        }
    }
}

/*
 *----------------------------------------------------------------------
 *
 * DupCmdNameInternalRep --
 *
 *	Initialize the internal representation of an cmdName Tcl_Obj to a
 *	copy of the internal representation of an existing cmdName object. 
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	"copyPtr"s internal rep is set to point to the ResolvedCmdName
 *	structure corresponding to "srcPtr"s internal rep. Increments the







|

|


















|







|













|







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
 *	representation.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Decrements the ref count of any cached ResolvedCmdName structure
 *	pointed to by the cmdName's internal representation. If this is
 *	the last use of the ResolvedCmdName, it is freed. This in turn
 *	decrements the ref count of the Command structure pointed to by
 *	the ResolvedSymbol, which may free the Command structure.
 *
 *----------------------------------------------------------------------
 */

static void
FreeCmdNameInternalRep(objPtr)
    register Tcl_Obj *objPtr;	/* CmdName object with internal
				 * representation to free. */
{
    register ResolvedCmdName *resPtr =
	(ResolvedCmdName *) objPtr->internalRep.twoPtrValue.ptr1;

    if (resPtr != NULL) {
	/*
	 * Decrement the reference count of the ResolvedCmdName structure.
	 * If there are no more uses, free the ResolvedCmdName structure.
	 */

        resPtr->refCount--;
        if (resPtr->refCount == 0) {
            /*
	     * Now free the cached command, unless it is still in its
             * hash table or if there are other references to it
             * from other cmdName objects.
	     */

            Command *cmdPtr = resPtr->cmdPtr;
            TclCleanupCommand(cmdPtr);
            ckfree((char *) resPtr);
        }
    }
}

/*
 *----------------------------------------------------------------------
 *
 * DupCmdNameInternalRep --
 *
 *	Initialize the internal representation of an cmdName Tcl_Obj to a
 *	copy of the internal representation of an existing cmdName object.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	"copyPtr"s internal rep is set to point to the ResolvedCmdName
 *	structure corresponding to "srcPtr"s internal rep. Increments the
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
    cmd = Tcl_FindCommand(interp, name, (Tcl_Namespace *) NULL,
	    /*flags*/ 0);
    cmdPtr = (Command *) cmd;
    if (cmdPtr != NULL) {
	/*
	 * Get the current namespace.
	 */
	
	if (iPtr->varFramePtr != NULL) {
	    currNsPtr = iPtr->varFramePtr->nsPtr;
	} else {
	    currNsPtr = iPtr->globalNsPtr;
	}
	
	cmdPtr->refCount++;
        resPtr = (ResolvedCmdName *) ckalloc(sizeof(ResolvedCmdName));
        resPtr->cmdPtr        = cmdPtr;
        resPtr->refNsPtr      = currNsPtr;
        resPtr->refNsId       = currNsPtr->nsId;
        resPtr->refNsCmdEpoch = currNsPtr->cmdRefEpoch;
        resPtr->cmdEpoch      = cmdPtr->cmdEpoch;
        resPtr->refCount      = 1;
    } else {
	resPtr = NULL;	/* no command named "name" was found */
    }

    /*
     * Free the old internalRep before setting the new one. We do this as
     * late as possible to allow the conversion code, in particular
     * GetStringFromObj, to use that old internalRep. If no Command
     * structure was found, leave NULL as the cached value.
     */

    if ((objPtr->typePtr != NULL)
	    && (objPtr->typePtr->freeIntRepProc != NULL)) {
	objPtr->typePtr->freeIntRepProc(objPtr);
    }
    
    objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) resPtr;
    objPtr->internalRep.twoPtrValue.ptr2 = NULL;
    objPtr->typePtr = &tclCmdNameType;
    return TCL_OK;
}







|





|


|
|
|
|
|
|















|





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
    cmd = Tcl_FindCommand(interp, name, (Tcl_Namespace *) NULL,
	    /*flags*/ 0);
    cmdPtr = (Command *) cmd;
    if (cmdPtr != NULL) {
	/*
	 * Get the current namespace.
	 */

	if (iPtr->varFramePtr != NULL) {
	    currNsPtr = iPtr->varFramePtr->nsPtr;
	} else {
	    currNsPtr = iPtr->globalNsPtr;
	}

	cmdPtr->refCount++;
        resPtr = (ResolvedCmdName *) ckalloc(sizeof(ResolvedCmdName));
        resPtr->cmdPtr		= cmdPtr;
        resPtr->refNsPtr	= currNsPtr;
        resPtr->refNsId		= currNsPtr->nsId;
        resPtr->refNsCmdEpoch	= currNsPtr->cmdRefEpoch;
        resPtr->cmdEpoch	= cmdPtr->cmdEpoch;
        resPtr->refCount	= 1;
    } else {
	resPtr = NULL;	/* no command named "name" was found */
    }

    /*
     * Free the old internalRep before setting the new one. We do this as
     * late as possible to allow the conversion code, in particular
     * GetStringFromObj, to use that old internalRep. If no Command
     * structure was found, leave NULL as the cached value.
     */

    if ((objPtr->typePtr != NULL)
	    && (objPtr->typePtr->freeIntRepProc != NULL)) {
	objPtr->typePtr->freeIntRepProc(objPtr);
    }

    objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) resPtr;
    objPtr->internalRep.twoPtrValue.ptr2 = NULL;
    objPtr->typePtr = &tclCmdNameType;
    return TCL_OK;
}
Changes to generic/tclParse.c.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 * Copyright (c) 1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 Ajuba Solutions.
 * Contributions from Don Porter, NIST, 2002. (not subject to US copyright)
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclParse.c,v 1.27.2.1 2003/05/22 19:12:07 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * The following table provides parsing information about each possible







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 * Copyright (c) 1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 Ajuba Solutions.
 * Contributions from Don Porter, NIST, 2002. (not subject to US copyright)
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclParse.c,v 1.27.2.2 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * The following table provides parsing information about each possible
603
604
605
606
607
608
609


610
611
612
613
614
615
616
    /*
     * The following loop parses the words of the command, one word
     * in each iteration through the loop.
     */

    parsePtr->commandStart = src;
    while (1) {


	/*
	 * Create the token for the word.
	 */

	TclGrowParseTokenArray(parsePtr,1);
	wordIndex = parsePtr->numTokens;
	tokenPtr = &parsePtr->tokenPtr[wordIndex];







>
>







603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
    /*
     * The following loop parses the words of the command, one word
     * in each iteration through the loop.
     */

    parsePtr->commandStart = src;
    while (1) {
	int expandWord = 0;

	/*
	 * Create the token for the word.
	 */

	TclGrowParseTokenArray(parsePtr,1);
	wordIndex = parsePtr->numTokens;
	tokenPtr = &parsePtr->tokenPtr[wordIndex];
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
	    break;
	}
	tokenPtr->start = src;
	parsePtr->numTokens++;
	parsePtr->numWords++;

	/*
	 * At this point the word can have one of three forms: something
	 * enclosed in quotes, something enclosed in braces, or an
	 * unquoted word (anything else).
	 */


	if (*src == '"') {
	    if (ParseQuotedString(interp, src, numBytes,
		    parsePtr, flags | PARSE_APPEND, &termPtr) != TCL_OK) {
		goto error;
	    }
	    src = termPtr; numBytes = parsePtr->end - src;
	} else if (*src == '{') {





	    if (ParseBraces(interp, src, numBytes,
		    parsePtr, flags | PARSE_APPEND, &termPtr) != TCL_OK) {
		goto error;
	    }
	    src = termPtr; numBytes = parsePtr->end - src;

























	} else {
	    /*
	     * This is an unquoted word.  Call ParseTokens and let it do
	     * all of the work.
	     */

	    if (ParseTokens(src, numBytes, TYPE_SPACE|terminators,







|
|
|


>







>
>
>
>
>





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







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
	    break;
	}
	tokenPtr->start = src;
	parsePtr->numTokens++;
	parsePtr->numWords++;

	/*
	 * At this point the word can have one of four forms: something
	 * enclosed in quotes, something enclosed in braces, and
	 * expanding word, or an unquoted word (anything else).
	 */

parseWord:
	if (*src == '"') {
	    if (ParseQuotedString(interp, src, numBytes,
		    parsePtr, flags | PARSE_APPEND, &termPtr) != TCL_OK) {
		goto error;
	    }
	    src = termPtr; numBytes = parsePtr->end - src;
	} else if (*src == '{') {
	    static char expPfx[] = "expand";
	    CONST size_t expPfxLen = sizeof(expPfx) - 1;
	    int expIdx = wordIndex + 1;
	    Tcl_Token *expPtr;

	    if (ParseBraces(interp, src, numBytes,
		    parsePtr, flags | PARSE_APPEND, &termPtr) != TCL_OK) {
		goto error;
	    }
	    src = termPtr; numBytes = parsePtr->end - src;

	    /* 
	     * Check whether the braces contained
	     * the word expansion prefix.
	     */

	    expPtr = &parsePtr->tokenPtr[expIdx];
	    if ( (expPfxLen == (size_t) expPtr->size)
					/* Same length as prefix */
		    && (0 == expandWord)
		    			/* Haven't seen prefix already */
		    && (1 == parsePtr->numTokens - expIdx)
	    				/* Only one token */
		    && (0 == strncmp(expPfx,expPtr->start,expPfxLen))
					/* Is the prefix */
		    && (numBytes > 0)
		    && (TclParseWhiteSpace(termPtr, numBytes, parsePtr, &type)
			    == 0)
		    && (type != TYPE_COMMAND_END)
					/* Non-whitespace follows */
		    ) {
		expandWord = 1;
		parsePtr->numTokens--;
		goto parseWord;
	    }
	} else {
	    /*
	     * This is an unquoted word.  Call ParseTokens and let it do
	     * all of the work.
	     */

	    if (ParseTokens(src, numBytes, TYPE_SPACE|terminators,
676
677
678
679
680
681
682



683
684
685
686
687
688
689
	tokenPtr = &parsePtr->tokenPtr[wordIndex];
	tokenPtr->size = src - tokenPtr->start;
	tokenPtr->numComponents = parsePtr->numTokens - (wordIndex + 1);
	if ((tokenPtr->numComponents == 1)
		&& (tokenPtr[1].type == TCL_TOKEN_TEXT)) {
	    tokenPtr->type = TCL_TOKEN_SIMPLE_WORD;
	}




	/*
	 * Do two additional checks: (a) make sure we're really at the
	 * end of a word (there might have been garbage left after a
	 * quoted or braced word), and (b) check for the end of the
	 * command.
	 */







>
>
>







709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
	tokenPtr = &parsePtr->tokenPtr[wordIndex];
	tokenPtr->size = src - tokenPtr->start;
	tokenPtr->numComponents = parsePtr->numTokens - (wordIndex + 1);
	if ((tokenPtr->numComponents == 1)
		&& (tokenPtr[1].type == TCL_TOKEN_TEXT)) {
	    tokenPtr->type = TCL_TOKEN_SIMPLE_WORD;
	}
	if (expandWord) {
	    tokenPtr->type = TCL_TOKEN_EXPAND_WORD;
	}

	/*
	 * Do two additional checks: (a) make sure we're really at the
	 * end of a word (there might have been garbage left after a
	 * quoted or braced word), and (b) check for the end of the
	 * command.
	 */
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
	    numBytes -= tokenPtr->size;
	} else if (*src == 0) {
	    tokenPtr->type = TCL_TOKEN_TEXT;
	    tokenPtr->size = 1;
	    parsePtr->numTokens++;
	    src++; numBytes--;
	} else {
	    panic("ParseTokens encountered unknown character");
	}
    }
    if (parsePtr->numTokens == originalTokens) {
	/*
	 * There was nothing in this range of text.  Add an empty token
	 * for the empty range, so that there is always at least one
	 * token added.







|







1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
	    numBytes -= tokenPtr->size;
	} else if (*src == 0) {
	    tokenPtr->type = TCL_TOKEN_TEXT;
	    tokenPtr->size = 1;
	    parsePtr->numTokens++;
	    src++; numBytes--;
	} else {
	    Tcl_Panic("ParseTokens encountered unknown character");
	}
    }
    if (parsePtr->numTokens == originalTokens) {
	/*
	 * There was nothing in this range of text.  Add an empty token
	 * for the empty range, so that there is always at least one
	 * token added.
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
}

/*
 *----------------------------------------------------------------------
 *
 * CommandComplete --
 *
 *      This procedure is shared by TclCommandComplete and
 *      Tcl_ObjCommandcoComplete; it does all the real work of seeing
 *      whether a script is complete
 *
 * Results:
 *      1 is returned if the script is complete, 0 if there are open
 *      delimiters such as " or (. 1 is also returned if there is a
 *      parse error in the script other than unmatched delimiters.
 *
 * Side effects:







|
|
|







2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
}

/*
 *----------------------------------------------------------------------
 *
 * CommandComplete --
 *
 *	This procedure is shared by TclCommandComplete and
 *	Tcl_ObjCommandComplete; it does all the real work of seeing
 *	whether a script is complete
 *
 * Results:
 *      1 is returned if the script is complete, 0 if there are open
 *      delimiters such as " or (. 1 is also returned if there is a
 *      parse error in the script other than unmatched delimiters.
 *
 * Side effects:
Changes to generic/tclPathObj.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33


34
35
36
37
38
39
40
/* 
 * tclPathObj.c --
 *
 *	This file contains the implementation of Tcl's "path" object
 *	type used to represent and manipulate a general (virtual)
 *	filesystem entity in an efficient manner.
 *
 * Copyright (c) 2003 Vince Darley.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclPathObj.c,v 1.3.2.3 2003/10/16 02:28:02 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#ifdef MAC_TCL
#include "tclMacInt.h"
#endif
#include "tclFileSystem.h"

/*
 * Prototypes for procedures defined later in this file.
 */

static void	DupFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr,
						  Tcl_Obj *copyPtr));
static void	FreeFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *listPtr));
static void	UpdateStringOfFsPath  _ANSI_ARGS_((Tcl_Obj *objPtr));
static int	SetFsPathFromAny _ANSI_ARGS_((Tcl_Interp *interp,
					      Tcl_Obj *objPtr));
static int	FindSplitPos _ANSI_ARGS_((char *path, char *separator));




/*
 * Define the 'path' object type, which Tcl uses to represent
 * file paths internally.
 */
Tcl_ObjType tclFsPathType = {












|















|
|

|
|
>
>







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
/* 
 * tclPathObj.c --
 *
 *	This file contains the implementation of Tcl's "path" object
 *	type used to represent and manipulate a general (virtual)
 *	filesystem entity in an efficient manner.
 *
 * Copyright (c) 2003 Vince Darley.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclPathObj.c,v 1.3.2.4 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#ifdef MAC_TCL
#include "tclMacInt.h"
#endif
#include "tclFileSystem.h"

/*
 * Prototypes for procedures defined later in this file.
 */

static void	DupFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *srcPtr,
						  Tcl_Obj *copyPtr));
static void	FreeFsPathInternalRep _ANSI_ARGS_((Tcl_Obj *pathPtr));
static void	UpdateStringOfFsPath  _ANSI_ARGS_((Tcl_Obj *pathPtr));
static int	SetFsPathFromAny _ANSI_ARGS_((Tcl_Interp *interp,
					      Tcl_Obj *pathPtr));
static int	FindSplitPos _ANSI_ARGS_((CONST char *path, int separator));
static int      IsSeparatorOrNull _ANSI_ARGS_((int ch));
static Tcl_Obj* GetExtension _ANSI_ARGS_((Tcl_Obj *pathPtr));


/*
 * Define the 'path' object type, which Tcl uses to represent
 * file paths internally.
 */
Tcl_ObjType tclFsPathType = {
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
 * struct FsPath --
 * 
 * Internal representation of a Tcl_Obj of "path" type.  This
 * can be used to represent relative or absolute paths, and has
 * certain optimisations when used to represent paths which are
 * already normalized and absolute.
 * 
 * Note that 'normPathPtr' can be a circular reference to the
 * container Tcl_Obj of this FsPath.

















 */
typedef struct FsPath {
    Tcl_Obj *translatedPathPtr; /* Name without any ~user sequences.
				 * If this is NULL, then this is a 
				 * pure normalized, absolute path
				 * object, in which the parent Tcl_Obj's
				 * string rep is already both translated
				 * and normalized. */
    Tcl_Obj *normPathPtr;       /* Normalized absolute path, without 
				 * ., .. or ~user sequences. If the 
				 * Tcl_Obj containing 
				 * this FsPath is already normalized, 
				 * this may be a circular reference back
				 * to the container.  If that is NOT the
				 * case, we have a refCount on the object. */
    Tcl_Obj *cwdPtr;            /* If null, path is absolute, else
				 * this points to the cwd object used
				 * for this path.  We have a refCount
				 * on the object. */
    int flags;                  /* Flags to describe interpretation */

    ClientData nativePathPtr;   /* Native representation of this path,
				 * which is filesystem dependent. */
    int filesystemEpoch;        /* Used to ensure the path representation
				 * was generated during the correct
				 * filesystem epoch.  The epoch changes
				 * when filesystem-mounts are changed. */ 
    struct FilesystemRecord *fsRecPtr;
				/* Pointer to the filesystem record 
				 * entry to use for this path. */
} FsPath;






/* 
 * Define some macros to give us convenient access to path-object
 * specific fields.
 */
#define PATHOBJ(objPtr) (objPtr->internalRep.otherValuePtr)
#define PATHFLAGS(objPtr) \
 (((FsPath*)(objPtr->internalRep.otherValuePtr))->flags)

#define TCLPATH_APPENDED 1
#define TCLPATH_RELATIVE 2

/*
 *---------------------------------------------------------------------------
 *
 * TclFSNormalizeAbsolutePath --
 *
 * Description:
 *	Takes an absolute path specification and computes a 'normalized'
 *	path from it.
 *	
 *	A normalized path is one which has all '../', './' removed.
 *	Also it is one which is in the 'standard' format for the native
 *	platform.  On MacOS, Unix, this means the path must be free of
 *	symbolic links/aliases, and on Windows it means we want the
 *	long form, with that long form's case-dependence (which gives
 *	us a unique, case-dependent path).
 *	
 *	The behaviour of this function if passed a non-absolute path
 *	is NOT defined.



 *
 * Results:
 *	The result is returned in a Tcl_Obj with a refCount of 1,
 *	which is therefore owned by the caller.  It must be
 *	freed (with Tcl_DecrRefCount) by the caller when no longer needed.
 *
 * Side effects:
 *	None (beyond the memory allocation for the result).
 *
 * Special note:
 *	This code is based on code from Matt Newman and Jean-Claude

 *	Wippler, with additions from Vince Darley and is copyright 
 *	those respective authors.
 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj*
TclFSNormalizeAbsolutePath(interp, pathPtr, clientDataPtr)
    Tcl_Interp* interp;    /* Interpreter to use */
    Tcl_Obj *pathPtr;      /* Absolute path to normalize */
    ClientData *clientDataPtr;




{
    int splen = 0, nplen, eltLen, i;

    char *eltName;



    Tcl_Obj *retVal;

    Tcl_Obj *split;


















    Tcl_Obj *elt;
















    













    /* Split has refCount zero */














    split = Tcl_FSSplitPath(pathPtr, &splen);






    /* 









     * Modify the list of entries in place, by removing '.', and
     * removing '..' and the entry before -- unless that entry before
     * is the top-level entry, i.e. the name of a volume.
     */




















    nplen = 0;




    for (i = 0; i < splen; i++) {
	Tcl_ListObjIndex(NULL, split, nplen, &elt);







	eltName = Tcl_GetStringFromObj(elt, &eltLen);


















	if ((eltLen == 1) && (eltName[0] == '.')) {



	    Tcl_ListObjReplace(NULL, split, nplen, 1, 0, NULL);



	} else if ((eltLen == 2)


		&& (eltName[0] == '.') && (eltName[1] == '.')) {
	    if (nplen > 1) {









		nplen--;

		Tcl_ListObjReplace(NULL, split, nplen, 2, 0, NULL);
	    } else {

		Tcl_ListObjReplace(NULL, split, nplen, 1, 0, NULL);
	    }

	} else {




	    nplen++;






	}

    }
    if (nplen > 0) {
	ClientData clientData = NULL;
	
	retVal = Tcl_FSJoinPath(split, nplen);
	/* 
	 * Now we have an absolute path, with no '..', '.' sequences,
	 * but it still may not be in 'unique' form, depending on the
	 * platform.  For instance, Unix is case-sensitive, so the
	 * path is ok.  Windows is case-insensitive, and also has the
	 * weird 'longname/shortname' thing (e.g. C:/Program Files/ and
	 * C:/Progra~1/ are equivalent).  MacOS is case-insensitive.
	 * 
	 * Virtual file systems which may be registered may have
	 * other criteria for normalizing a path.
	 */
	Tcl_IncrRefCount(retVal);
	TclFSNormalizeToUniquePath(interp, retVal, 0, &clientData);
	/* 
	 * Since we know it is a normalized path, we can
	 * actually convert this object into an FsPath for
	 * greater efficiency 
	 */
	TclFSMakePathFromNormalized(interp, retVal, clientData);
	if (clientDataPtr != NULL) {
	    *clientDataPtr = clientData;
	}
    } else {
	/* Init to an empty string */
	retVal = Tcl_NewStringObj("",0);
	Tcl_IncrRefCount(retVal);
    }
    /* 
     * We increment and then decrement the refCount of split to free
     * it.  We do this right at the end, in case there are
     * optimisations in Tcl_FSJoinPath(split, nplen) above which would
     * let it make use of split more effectively if it has a refCount
     * of zero.  Also we can't just decrement the ref count, in case
     * 'split' was actually returned by the join call above, in a
     * single-element optimisation when nplen == 1.
     */
    Tcl_IncrRefCount(split);
    Tcl_DecrRefCount(split);

    /* This has a refCount of 1 for the caller */
    return retVal;
}

/*
 *----------------------------------------------------------------------
 *







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



















|
>











>
>
>
>
>




|
|
|

<
<



















>
>
>










|
>
|
<





|
|
|
>
>
>
>

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







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
 * struct FsPath --
 * 
 * Internal representation of a Tcl_Obj of "path" type.  This
 * can be used to represent relative or absolute paths, and has
 * certain optimisations when used to represent paths which are
 * already normalized and absolute.
 * 
 * Note that both 'translatedPathPtr' and 'normPathPtr' can be a
 * circular reference to the container Tcl_Obj of this FsPath.
 * 
 * There are two cases, with the first being the most common:
 * 
 * (i) flags == 0, => Ordinary path.  
 * 
 * translatedPathPtr contains the translated path (which may be
 * a circular reference to the object itself).  If it is NULL
 * then the path is pure normalized (and the normPathPtr will be
 * a circular reference).  cwdPtr is null for an absolute path,
 * and non-null for a relative path (unless the cwd has never been
 * set, in which case the cwdPtr may also be null for a relative path).
 * 
 * (ii) flags != 0, => Special path, see TclNewFSPathObj
 * 
 * Now, this is a path like 'file join $dir $tail' where, cwdPtr is
 * the $dir and normPathPtr is the $tail.
 * 
 */
typedef struct FsPath {
    Tcl_Obj *translatedPathPtr; /* Name without any ~user sequences.
				 * If this is NULL, then this is a 
				 * pure normalized, absolute path
				 * object, in which the parent Tcl_Obj's
				 * string rep is already both translated
				 * and normalized. */
    Tcl_Obj *normPathPtr;       /* Normalized absolute path, without 
				 * ., .. or ~user sequences. If the 
				 * Tcl_Obj containing 
				 * this FsPath is already normalized, 
				 * this may be a circular reference back
				 * to the container.  If that is NOT the
				 * case, we have a refCount on the object. */
    Tcl_Obj *cwdPtr;            /* If null, path is absolute, else
				 * this points to the cwd object used
				 * for this path.  We have a refCount
				 * on the object. */
    int flags;                  /* Flags to describe interpretation -
                                 * see below. */
    ClientData nativePathPtr;   /* Native representation of this path,
				 * which is filesystem dependent. */
    int filesystemEpoch;        /* Used to ensure the path representation
				 * was generated during the correct
				 * filesystem epoch.  The epoch changes
				 * when filesystem-mounts are changed. */ 
    struct FilesystemRecord *fsRecPtr;
				/* Pointer to the filesystem record 
				 * entry to use for this path. */
} FsPath;

/*
 * Flag values for FsPath->flags.
 */
#define TCLPATH_APPENDED 1

/* 
 * Define some macros to give us convenient access to path-object
 * specific fields.
 */
#define PATHOBJ(pathPtr) (pathPtr->internalRep.otherValuePtr)
#define PATHFLAGS(pathPtr) \
 (((FsPath*)(pathPtr->internalRep.otherValuePtr))->flags)




/*
 *---------------------------------------------------------------------------
 *
 * TclFSNormalizeAbsolutePath --
 *
 * Description:
 *	Takes an absolute path specification and computes a 'normalized'
 *	path from it.
 *	
 *	A normalized path is one which has all '../', './' removed.
 *	Also it is one which is in the 'standard' format for the native
 *	platform.  On MacOS, Unix, this means the path must be free of
 *	symbolic links/aliases, and on Windows it means we want the
 *	long form, with that long form's case-dependence (which gives
 *	us a unique, case-dependent path).
 *	
 *	The behaviour of this function if passed a non-absolute path
 *	is NOT defined.
 *	
 *	pathPtr may have a refCount of zero, or may be a shared
 *	object.
 *
 * Results:
 *	The result is returned in a Tcl_Obj with a refCount of 1,
 *	which is therefore owned by the caller.  It must be
 *	freed (with Tcl_DecrRefCount) by the caller when no longer needed.
 *
 * Side effects:
 *	None (beyond the memory allocation for the result).
 *
 * Special note:
 *	This code was originally based on code from Matt Newman and
 *	Jean-Claude Wippler, but has since been totally rewritten by
 *	Vince Darley to deal with symbolic links.

 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj*
TclFSNormalizeAbsolutePath(interp, pathPtr, clientDataPtr)
    Tcl_Interp* interp;        /* Interpreter to use */
    Tcl_Obj *pathPtr;          /* Absolute path to normalize */
    ClientData *clientDataPtr; /* If non-NULL, then may be set to the
                                * fs-specific clientData for this path.
                                * This will happen when that extra
                                * information can be calculated efficiently
                                * as a side-effect of normalization. */
{

    ClientData clientData = NULL;
    CONST char *dirSep, *oldDirSep;
    int first = 1;   /* Set to zero once we've passed the first
                      * directory separator - we can't use '..' to 
                      * remove the volume in a path. */
    Tcl_Obj *retVal = NULL;
    dirSep = Tcl_GetString(pathPtr);
    
    if (tclPlatform == TCL_PLATFORM_WINDOWS) {
        if (dirSep[0] != 0 && dirSep[1] == ':' && 
	    (dirSep[2] == '/' || dirSep[2] == '\\')) {
	    /* Do nothing */
	} else if ((dirSep[0] == '/' || dirSep[0] == '\\') 
	    && (dirSep[1] == '/' || dirSep[1] == '\\')) {
	    /* 
	     * UNC style path, where we must skip over the
	     * first separator, since the first two segments
	     * are actually inseparable.
	     */
	    dirSep += 2;
	    dirSep += FindSplitPos(dirSep, '/');
	    if (*dirSep != 0) {
	        dirSep++;
	    }
	}
    }
    
    /* 
     * Scan forward from one directory separator to the next,
     * checking for '..' and '.' sequences which must be handled
     * specially.  In particular handling of '..' can be complicated
     * if the directory before is a link, since we will have to
     * expand the link to be able to back up one level.
     */
    while (*dirSep != 0) {
	oldDirSep = dirSep;
	if (!first) {
	    dirSep++;
	}
        dirSep += FindSplitPos(dirSep, '/');
	if (dirSep[0] == 0 || dirSep[1] == 0) {
	    if (retVal != NULL) {
		Tcl_AppendToObj(retVal, oldDirSep, dirSep - oldDirSep);
	    }
	    break;
	}
	if (dirSep[1] == '.') {
	    if (retVal != NULL) {
		Tcl_AppendToObj(retVal, oldDirSep, dirSep - oldDirSep);
		oldDirSep = dirSep;
	    }
	  again:
	    if (IsSeparatorOrNull(dirSep[2])) {
		/* Need to skip '.' in the path */
		if (retVal == NULL) {
		    CONST char *path = Tcl_GetString(pathPtr);
		    retVal = Tcl_NewStringObj(path, dirSep - path);
		    Tcl_IncrRefCount(retVal);
		}
		dirSep += 2;
		oldDirSep = dirSep;
		if (dirSep[0] != 0 && dirSep[1] == '.') {
		    goto again;
		}
		continue;
	    }
	    if (dirSep[2] == '.' && IsSeparatorOrNull(dirSep[3])) {
		Tcl_Obj *link;
		int curLen;
		char *linkStr;
		/* Have '..' so need to skip previous directory */
		if (retVal == NULL) {
		    CONST char *path = Tcl_GetString(pathPtr);
		    retVal = Tcl_NewStringObj(path, dirSep - path);
		    Tcl_IncrRefCount(retVal);
		}
		if (!first || (tclPlatform == TCL_PLATFORM_UNIX)) {
		    link = Tcl_FSLink(retVal, NULL, 0);
		    if (link != NULL) {
			/* 
			 * Got a link.  Need to check if the link
			 * is relative or absolute, for those platforms
			 * where relative links exist.
			 */
			if ((tclPlatform != TCL_PLATFORM_WINDOWS)
			   && (Tcl_FSGetPathType(link) == TCL_PATH_RELATIVE)) {
			    /* 
			     * We need to follow this link which is
			     * relative to retVal's directory.  This
			     * means concatenating the link onto

			     * the directory of the path so far.
			     */
			    CONST char *path = Tcl_GetStringFromObj(retVal, 
								    &curLen);
			    while (--curLen >= 0) {
			        if (IsSeparatorOrNull(path[curLen])) {
			            break;
			        }
			    }
			    if (Tcl_IsShared(retVal)) {
				Tcl_DecrRefCount(retVal);
				retVal = Tcl_DuplicateObj(retVal);
				Tcl_IncrRefCount(retVal);
			    }
			    /* We want the trailing slash */
			    Tcl_SetObjLength(retVal, curLen+1);
			    Tcl_AppendObjToObj(retVal, link);
			    Tcl_DecrRefCount(link);
			    linkStr = Tcl_GetStringFromObj(retVal, &curLen);
			} else {
			    /* Absolute link */
			    Tcl_DecrRefCount(retVal);
			    retVal = link;
			    linkStr = Tcl_GetStringFromObj(retVal, &curLen);
			    /* Convert to forward-slashes on windows */
			    if (tclPlatform == TCL_PLATFORM_WINDOWS) {
				int i;
				for (i = 0; i < curLen; i++) {

				    if (linkStr[i] == '\\') {
					linkStr[i] = '/';
				    }
				}
			    }
			}
		    } else {
			linkStr = Tcl_GetStringFromObj(retVal, &curLen);
		    }
		    /* Either way, we now remove the last path element */
		    while (--curLen >= 0) {
			if (IsSeparatorOrNull(linkStr[curLen])) {
			    Tcl_SetObjLength(retVal, curLen);
			    break;
			}
		    }
		}
		dirSep += 3;
		oldDirSep = dirSep;
		if (dirSep[0] != 0 && dirSep[1] == '.') {
		    goto again;
		}
		continue;
	    }
	}
	first = 0;
	if (retVal != NULL) {
	    Tcl_AppendToObj(retVal, oldDirSep, dirSep - oldDirSep);
	}
    }
    
    /* 
     * If we didn't make any changes, just use the input path 
     */
    if (retVal == NULL) {
	retVal = pathPtr;
	Tcl_IncrRefCount(retVal);
	
	if (Tcl_IsShared(retVal)) {
	    /* 
	     * Unfortunately, the platform-specific normalization code
	     * which will be called below has no way of dealing with the
	     * case where an object is shared.  It is expecting to
	     * modify an object in place.  So, we must duplicate this
	     * here to ensure an object with a single ref-count.
	     * 
	     * If that changes in the future (e.g. the normalize proc is
	     * given one object and is able to return a different one),
	     * then we could remove this code.
	     */
	    Tcl_DecrRefCount(retVal);

	    retVal = Tcl_DuplicateObj(pathPtr);
	    Tcl_IncrRefCount(retVal);
	}
    }

    /* 
     * Ensure a windows drive like C:/ has a trailing separator 
     */
    if (tclPlatform == TCL_PLATFORM_WINDOWS) {
	int len;
	CONST char *path = Tcl_GetStringFromObj(retVal, &len);
	if (len == 2 && path[0] != 0 && path[1] == ':') {
	    if (Tcl_IsShared(retVal)) {
		Tcl_DecrRefCount(retVal);
		retVal = Tcl_DuplicateObj(retVal);
		Tcl_IncrRefCount(retVal);
	    }
	    Tcl_AppendToObj(retVal, "/", 1);
	}


    }

    /* 
     * Now we have an absolute path, with no '..', '.' sequences,
     * but it still may not be in 'unique' form, depending on the
     * platform.  For instance, Unix is case-sensitive, so the
     * path is ok.  Windows is case-insensitive, and also has the
     * weird 'longname/shortname' thing (e.g. C:/Program Files/ and
     * C:/Progra~1/ are equivalent).  MacOS is case-insensitive.
     * 
     * Virtual file systems which may be registered may have
     * other criteria for normalizing a path.
     */

    TclFSNormalizeToUniquePath(interp, retVal, 0, &clientData);
    /* 
     * Since we know it is a normalized path, we can
     * actually convert this object into an FsPath for
     * greater efficiency 
     */
    TclFSMakePathFromNormalized(interp, retVal, clientData);
    if (clientDataPtr != NULL) {
	*clientDataPtr = clientData;
    }

















    /* This has a refCount of 1 for the caller */
    return retVal;
}

/*
 *----------------------------------------------------------------------
 *
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

Tcl_PathType
Tcl_FSGetPathType(pathObjPtr)
    Tcl_Obj *pathObjPtr;
{
    return TclFSGetPathType(pathObjPtr, NULL, NULL);
}

/*
 *----------------------------------------------------------------------
 *
 * TclFSGetPathType --
 *







|
|

|







397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

Tcl_PathType
Tcl_FSGetPathType(pathPtr)
    Tcl_Obj *pathPtr;
{
    return TclFSGetPathType(pathPtr, NULL, NULL);
}

/*
 *----------------------------------------------------------------------
 *
 * TclFSGetPathType --
 *
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
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

Tcl_PathType
TclFSGetPathType(pathObjPtr, filesystemPtrPtr, driveNameLengthPtr)
    Tcl_Obj *pathObjPtr;
    Tcl_Filesystem **filesystemPtrPtr;
    int *driveNameLengthPtr;
{
    if (Tcl_FSConvertToPathType(NULL, pathObjPtr) != TCL_OK) {
	return TclGetPathType(pathObjPtr, filesystemPtrPtr, 
		driveNameLengthPtr, NULL);
    } else {
	FsPath *fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr);
	if (fsPathPtr->cwdPtr != NULL) {
	    if (PATHFLAGS(pathObjPtr) == 0) {
		return TCL_PATH_RELATIVE;
	    }
	    return TclFSGetPathType(fsPathPtr->cwdPtr, filesystemPtrPtr, 
		    driveNameLengthPtr);
	} else {
	    return TclGetPathType(pathObjPtr, filesystemPtrPtr, 
		    driveNameLengthPtr, NULL);
	}
    }
}














































































































































































































/*
 *---------------------------------------------------------------------------
 *
 * Tcl_FSJoinPath --
 *
 *      This function takes the given Tcl_Obj, which should be a valid
 *      list, and returns the path object given by considering the
 *      first 'elements' elements as valid path segments.  If elements < 0,
 *      we use the entire list.




 *      
 * Results:
 *      Returns object with refCount of zero, (or if non-zero, it has
 *      references elsewhere in Tcl).  Either way, the caller must
 *      increment its refCount before use.
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj* 
Tcl_FSJoinPath(listObj, elements)
    Tcl_Obj *listObj;
    int elements;
{
    Tcl_Obj *res;
    int i;
    Tcl_Filesystem *fsPtr = NULL;
    
    if (elements < 0) {
	if (Tcl_ListObjLength(NULL, listObj, &elements) != TCL_OK) {







|
|



|
|


|

|





|




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










>
>
>
>













|
|







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
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

Tcl_PathType
TclFSGetPathType(pathPtr, filesystemPtrPtr, driveNameLengthPtr)
    Tcl_Obj *pathPtr;
    Tcl_Filesystem **filesystemPtrPtr;
    int *driveNameLengthPtr;
{
    if (Tcl_FSConvertToPathType(NULL, pathPtr) != TCL_OK) {
	return TclGetPathType(pathPtr, filesystemPtrPtr, 
		driveNameLengthPtr, NULL);
    } else {
	FsPath *fsPathPtr = (FsPath*) PATHOBJ(pathPtr);
	if (fsPathPtr->cwdPtr != NULL) {
	    if (PATHFLAGS(pathPtr) == 0) {
		return TCL_PATH_RELATIVE;
	    }
	    return TclFSGetPathType(fsPathPtr->cwdPtr, filesystemPtrPtr, 
		    driveNameLengthPtr);
	} else {
	    return TclGetPathType(pathPtr, filesystemPtrPtr, 
		    driveNameLengthPtr, NULL);
	}
    }
}

/*
 *---------------------------------------------------------------------------
 *
 * TclPathPart
 *
 *	This procedure calculates the requested part of the the given
 *	path, which can be:
 *	
 *	- the directory above ('file dirname')
 *	- the tail            ('file tail')
 *	- the extension       ('file extension')
 *	- the root            ('file root')
 *	
 *	The 'portion' parameter dictates which of these to calculate.
 *	There are a number of special cases both to be more efficient,
 *	and because the behaviour when given a path with only a single
 *	element is defined to require the expansion of that single
 *	element, where possible.
 *
 *      Should look into integrating 'FileBasename' in tclFCmd.c into
 *      this function.
 *      
 * Results:
 *	NULL if an error occurred, otherwise a Tcl_Obj owned by
 *	the caller (i.e. most likely with refCount 1).
 *
 * Side effects:
 *      None.
 *
 *---------------------------------------------------------------------------
 */

Tcl_Obj*
TclPathPart(interp, pathPtr, portion)
    Tcl_Interp *interp;		/* Used for error reporting */
    Tcl_Obj *pathPtr;           /* Path to take dirname of */
    Tcl_PathPart portion;       /* Requested portion of name */
{
    if (pathPtr->typePtr == &tclFsPathType) {
	FsPath *fsPathPtr = (FsPath*) PATHOBJ(pathPtr);
	if (PATHFLAGS(pathPtr) != 0) {
	    switch (portion) {
		case TCL_PATH_DIRNAME: {
		    Tcl_IncrRefCount(fsPathPtr->cwdPtr);
		    return fsPathPtr->cwdPtr;
		}
		case TCL_PATH_TAIL: {
		    Tcl_IncrRefCount(fsPathPtr->normPathPtr);
		    return fsPathPtr->normPathPtr;
		}
		case TCL_PATH_EXTENSION: {
		    return GetExtension(fsPathPtr->normPathPtr);
		}
		case TCL_PATH_ROOT: {
		    /* Unimplemented */
		    CONST char *fileName, *extension;
		    int length;
		    fileName = Tcl_GetStringFromObj(fsPathPtr->normPathPtr, 
						    &length);
		    extension = TclGetExtension(fileName);
		    if (extension == NULL) {
			/* 
			 * There is no extension so the root is the
			 * same as the path we were given.
			 */
			Tcl_IncrRefCount(pathPtr);
			return pathPtr;
		    } else {
			/*
			 * Duplicate the object we were given and
			 * then trim off the extension of the
			 * tail component of the path.
			 */
			Tcl_Obj *root;
			FsPath *fsDupPtr;
			root = Tcl_DuplicateObj(pathPtr);
			Tcl_IncrRefCount(root);
			fsDupPtr = (FsPath*) PATHOBJ(root);
			if (Tcl_IsShared(fsDupPtr->normPathPtr)) {
			    Tcl_DecrRefCount(fsDupPtr->normPathPtr);
			    fsDupPtr->normPathPtr = Tcl_NewStringObj(fileName,
					     (int)(length - strlen(extension)));
			    Tcl_IncrRefCount(fsDupPtr->normPathPtr);
			} else {
			    Tcl_SetObjLength(fsDupPtr->normPathPtr, 
					     (int)(length - strlen(extension)));
			}
			return root;
		    }
		}
		default: {
		    /* We should never get here */
		    Tcl_Panic("Bad portion to TclPathPart");
		    /* For less clever compilers */
		    return NULL;
		}
	    }
	} else if (fsPathPtr->cwdPtr != NULL) {
	    /* Relative path */
	    goto standardPath;
	} else {
	    /* Absolute path */
	    goto standardPath;
	}
    } else {
	int splitElements;
	Tcl_Obj *splitPtr;
	Tcl_Obj *resultPtr = NULL;
      standardPath:

        if (portion == TCL_PATH_EXTENSION) {
	    return GetExtension(pathPtr);
        } else if (portion == TCL_PATH_ROOT) {
	    int length;
	    CONST char *fileName, *extension;
	    
	    fileName = Tcl_GetStringFromObj(pathPtr, &length);
	    extension = TclGetExtension(fileName);
	    if (extension == NULL) {
		Tcl_IncrRefCount(pathPtr);
		return pathPtr;
	    } else {
		Tcl_Obj *root = Tcl_NewStringObj(fileName, 
			(int) (length - strlen(extension)));
		Tcl_IncrRefCount(root);
		return root;
	    }
        }
        
	/* 
	 * The behaviour we want here is slightly different to
	 * the standard Tcl_FSSplitPath in the handling of home
	 * directories; Tcl_FSSplitPath preserves the "~" while 
	 * this code computes the actual full path name, if we
	 * had just a single component.
	 */    
	splitPtr = Tcl_FSSplitPath(pathPtr, &splitElements);
	Tcl_IncrRefCount(splitPtr);
	if ((splitElements == 1) && (Tcl_GetString(pathPtr)[0] == '~')) {
	    Tcl_Obj *norm;
	    
	    Tcl_DecrRefCount(splitPtr);
	    norm = Tcl_FSGetNormalizedPath(interp, pathPtr);
	    if (norm == NULL) {
		return NULL;
	    }
	    splitPtr = Tcl_FSSplitPath(norm, &splitElements);
	    Tcl_IncrRefCount(splitPtr);
	}
	if (portion == TCL_PATH_TAIL) {
	    /*
	     * Return the last component, unless it is the only component,
	     * and it is the root of an absolute path.
	     */

	    if ((splitElements > 0) && ((splitElements > 1)
	      || (Tcl_FSGetPathType(pathPtr) == TCL_PATH_RELATIVE))) {
		Tcl_ListObjIndex(NULL, splitPtr, splitElements-1, &resultPtr);
	    } else {
		resultPtr = Tcl_NewObj();
	    }
	} else {
	    /*
	     * Return all but the last component.  If there is only one
	     * component, return it if the path was non-relative, otherwise
	     * return the current directory.
	     */

	    if (splitElements > 1) {
		resultPtr = Tcl_FSJoinPath(splitPtr, splitElements - 1);
	    } else if (splitElements == 0 || 
	      (Tcl_FSGetPathType(pathPtr) == TCL_PATH_RELATIVE)) {
		resultPtr = Tcl_NewStringObj(
			((tclPlatform == TCL_PLATFORM_MAC) ? ":" : "."), 1);
	    } else {
		Tcl_ListObjIndex(NULL, splitPtr, 0, &resultPtr);
	    }
	}
	Tcl_IncrRefCount(resultPtr);
	Tcl_DecrRefCount(splitPtr);
	return resultPtr;
    }
}

/*
 * Simple helper function 
 */
static Tcl_Obj*
GetExtension(pathPtr) 
    Tcl_Obj *pathPtr;
{
    CONST char *tail, *extension;
    Tcl_Obj *ret;
    
    tail = Tcl_GetString(pathPtr);
    extension = TclGetExtension(tail);
    if (extension == NULL) {
	ret = Tcl_NewObj();
    } else {
	ret = Tcl_NewStringObj(extension, -1);
    }
    Tcl_IncrRefCount(ret);
    return ret;
}

/*
 *---------------------------------------------------------------------------
 *
 * Tcl_FSJoinPath --
 *
 *      This function takes the given Tcl_Obj, which should be a valid
 *      list, and returns the path object given by considering the
 *      first 'elements' elements as valid path segments.  If elements < 0,
 *      we use the entire list.
 *      
 *      It is possible that the returned object is actually an element
 *      of the given list, so the caller should be careful to store a
 *      refCount to it before freeing the list.
 *      
 * Results:
 *      Returns object with refCount of zero, (or if non-zero, it has
 *      references elsewhere in Tcl).  Either way, the caller must
 *      increment its refCount before use.
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj* 
Tcl_FSJoinPath(listObj, elements)
    Tcl_Obj *listObj;  /* Path elements to join, may have refCount 0 */
    int elements;      /* Number of elements to use (-1 = all) */
{
    Tcl_Obj *res;
    int i;
    Tcl_Filesystem *fsPtr = NULL;
    
    if (elements < 0) {
	if (Tcl_ListObjLength(NULL, listObj, &elements) != TCL_OK) {
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
	 * waste our time joining null elements to the path 
	 */
	if (elements > listTest) {
	    elements = listTest;
	}
    }
    
    res = Tcl_NewObj();
    
    for (i = 0; i < elements; i++) {
	Tcl_Obj *elt;
	int driveNameLength;
	Tcl_PathType type;
	char *strElt;
	int strEltLen;







|







708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
	 * waste our time joining null elements to the path 
	 */
	if (elements > listTest) {
	    elements = listTest;
	}
    }
    
    res = NULL;
    
    for (i = 0; i < elements; i++) {
	Tcl_Obj *elt;
	int driveNameLength;
	Tcl_PathType type;
	char *strElt;
	int strEltLen;
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
		str = Tcl_GetStringFromObj(tail,&len);
		if (len == 0) {
		    /* 
		     * This happens if we try to handle the root volume
		     * '/'.  There's no need to return a special path
		     * object, when the base itself is just fine!
		     */
		    Tcl_DecrRefCount(res);
		    return elt;
		}
		/* 
		 * If it doesn't begin with '.'  and is a mac or unix
		 * path or it a windows path without backslashes, then we
		 * can be very efficient here.  (In fact even a windows
		 * path with backslashes can be joined efficiently, but
		 * the path object would not have forward slashes only,
		 * and this would therefore contradict our 'file join'
		 * documentation).
		 */
		if (str[0] != '.' && ((tclPlatform != TCL_PLATFORM_WINDOWS) 
				      || (strchr(str, '\\') == NULL))) {
		    Tcl_DecrRefCount(res);
		    return TclNewFSPathObj(elt, str, len);
		}
		/* 
		 * Otherwise we don't have an easy join, and
		 * we must let the more general code below handle
		 * things
		 */
	    } else {
		if (tclPlatform == TCL_PLATFORM_UNIX) {
		    Tcl_DecrRefCount(res);
		    return tail;
		} else {
		    CONST char *str;
		    int len;
		    str = Tcl_GetStringFromObj(tail,&len);
		    if (tclPlatform == TCL_PLATFORM_WINDOWS) {
			if (strchr(str, '\\') == NULL) {
			    Tcl_DecrRefCount(res);
			    return tail;
			}
		    } else if (tclPlatform == TCL_PLATFORM_MAC) {
			if (strchr(str, '/') == NULL) {
			    Tcl_DecrRefCount(res);
			    return tail;
			}
		    }
		}
	    }
	}
	strElt = Tcl_GetStringFromObj(elt, &strEltLen);
	type = TclGetPathType(elt, &fsPtr, &driveNameLength, &driveName);
	if (type != TCL_PATH_RELATIVE) {
	    /* Zero out the current result */
	    Tcl_DecrRefCount(res);

	    if (driveName != NULL) {






		res = Tcl_DuplicateObj(driveName);
		Tcl_DecrRefCount(driveName);





	    } else {
		res = Tcl_NewStringObj(strElt, driveNameLength);
	    }
	    strElt += driveNameLength;
	}
	





























































	ptr = Tcl_GetStringFromObj(res, &length);



	
	/* 
	 * Strip off any './' before a tilde, unless this is the
	 * beginning of the path.
	 */
	if (length > 0 && strEltLen > 0) {
	    if ((strElt[0] == '.') && (strElt[1] == '/') 
	      && (strElt[2] == '~')) {
		strElt += 2;
	    }
	}

	/* 
	 * A NULL value for fsPtr at this stage basically means
	 * we're trying to join a relative path onto something
	 * which is also relative (or empty).  There's nothing
	 * particularly wrong with that.







|













|









|







|




|










|
>

>
>
>
>
>
>


>
>
>
>
>






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





|
|
<
|
<







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
		str = Tcl_GetStringFromObj(tail,&len);
		if (len == 0) {
		    /* 
		     * This happens if we try to handle the root volume
		     * '/'.  There's no need to return a special path
		     * object, when the base itself is just fine!
		     */
		    if (res != NULL) Tcl_DecrRefCount(res);
		    return elt;
		}
		/* 
		 * If it doesn't begin with '.'  and is a mac or unix
		 * path or it a windows path without backslashes, then we
		 * can be very efficient here.  (In fact even a windows
		 * path with backslashes can be joined efficiently, but
		 * the path object would not have forward slashes only,
		 * and this would therefore contradict our 'file join'
		 * documentation).
		 */
		if (str[0] != '.' && ((tclPlatform != TCL_PLATFORM_WINDOWS) 
				      || (strchr(str, '\\') == NULL))) {
		    if (res != NULL) Tcl_DecrRefCount(res);
		    return TclNewFSPathObj(elt, str, len);
		}
		/* 
		 * Otherwise we don't have an easy join, and
		 * we must let the more general code below handle
		 * things
		 */
	    } else {
		if (tclPlatform == TCL_PLATFORM_UNIX) {
		    if (res != NULL) Tcl_DecrRefCount(res);
		    return tail;
		} else {
		    CONST char *str;
		    int len;
		    str = Tcl_GetStringFromObj(tail,&len);
		    if (tclPlatform == TCL_PLATFORM_WINDOWS) {
			if (strchr(str, '\\') == NULL) {
			    if (res != NULL) Tcl_DecrRefCount(res);
			    return tail;
			}
		    } else if (tclPlatform == TCL_PLATFORM_MAC) {
			if (strchr(str, '/') == NULL) {
			    if (res != NULL) Tcl_DecrRefCount(res);
			    return tail;
			}
		    }
		}
	    }
	}
	strElt = Tcl_GetStringFromObj(elt, &strEltLen);
	type = TclGetPathType(elt, &fsPtr, &driveNameLength, &driveName);
	if (type != TCL_PATH_RELATIVE) {
	    /* Zero out the current result */
	    if (res != NULL) Tcl_DecrRefCount(res);

	    if (driveName != NULL) {
		/*
		 * We've been given a separate drive-name object,
		 * because the prefix in 'elt' is not in a suitable
		 * format for us (e.g. it may contain irrelevant
		 * multiple separators, like C://///foo).
		 */
		res = Tcl_DuplicateObj(driveName);
		Tcl_DecrRefCount(driveName);
		/* 
		 * Do not set driveName to NULL, because we will check
		 * its value below (but we won't access the contents,
		 * since those have been cleaned-up).
		 */
	    } else {
		res = Tcl_NewStringObj(strElt, driveNameLength);
	    }
	    strElt += driveNameLength;
	}
	
	/* 
	 * Optimisation block: if this is the last element to be
	 * examined, and it is absolute or the only element, and the
	 * drive-prefix was ok (if there is one), it might be that the
	 * path is already in a suitable form to be returned.  Then we
	 * can short-cut the rest of this procedure.
	 */
	if ((driveName == NULL) && (i == (elements - 1)) 
	  && (type != TCL_PATH_RELATIVE || res == NULL)) {
	    /* 
	     * It's the last path segment.  Perform a quick check if
	     * the path is already in a suitable form.
	     */
	    int equal = 1;
	    
	    if (tclPlatform == TCL_PLATFORM_WINDOWS) {
		if (strchr(strElt, '\\') != NULL) {
		    equal = 0;
		}
	    }
	    if (equal && (tclPlatform != TCL_PLATFORM_MAC)) {
		ptr = strElt;
		while (*ptr != '\0') {
		    if (*ptr == '/' && (ptr[1] == '/' || ptr[1] == '\0')) {
			equal = 0;
			break;
		    }
		    ptr++;
		}
	    }
	    if (equal && (tclPlatform == TCL_PLATFORM_MAC)) {
		/*
		 * If it contains any colons, then it mustn't contain
		 * any duplicates.  Otherwise, the path is in unix-form
		 * and is no good.
		 */
		if (strchr(strElt, ':') != NULL) {
		    ptr = strElt;
		    while (*ptr != '\0') {
			if (*ptr == ':' && (ptr[1] == ':' || ptr[1] == '\0')) {
			    equal = 0;
			    break;
			}
			ptr++;
		    }
		} else {
		    equal = 0;
		}
	    }
	    if (equal) {
		if (res != NULL) Tcl_DecrRefCount(res);
		/* 
		 * This element is just what we want to return already -
		 * no further manipulation is requred.
		 */
		return elt;
	    }
	}
	
	if (res == NULL) {
	    res = Tcl_NewObj();
	    ptr = Tcl_GetStringFromObj(res, &length);
	} else {
	    ptr = Tcl_GetStringFromObj(res, &length);
	}
	
	/* 
	 * Strip off any './' before a tilde, unless this is the
	 * beginning of the path.
	 */
	if (length > 0 && strEltLen > 0 
	  && (strElt[0] == '.') && (strElt[1] == '/') && (strElt[2] == '~')) {

	    strElt += 2;

	}

	/* 
	 * A NULL value for fsPtr at this stage basically means
	 * we're trying to join a relative path onto something
	 * which is also relative (or empty).  There's nothing
	 * particularly wrong with that.
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
 *
 * Side effects:
 *	The old representation may be freed, and new memory allocated.
 *
 *---------------------------------------------------------------------------
 */
int 
Tcl_FSConvertToPathType(interp, objPtr)
    Tcl_Interp *interp;		/* Interpreter in which to store error
				 * message (if necessary). */
    Tcl_Obj *objPtr;		/* Object to convert to a valid, current
				 * path type. */
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);

    /* 
     * While it is bad practice to examine an object's type directly,
     * this is actually the best thing to do here.  The reason is that
     * if we are converting this object to FsPath type for the first
     * time, we don't need to worry whether the 'cwd' has changed.
     * On the other hand, if this object is already of FsPath type,
     * and is a relative path, we do have to worry about the cwd.
     * If the cwd has changed, we must recompute the path.
     */
    if (objPtr->typePtr == &tclFsPathType) {
	FsPath *fsPathPtr = (FsPath*) PATHOBJ(objPtr);
	if (fsPathPtr->filesystemEpoch != tsdPtr->filesystemEpoch) {
	    if (objPtr->bytes == NULL) {
		UpdateStringOfFsPath(objPtr);
	    }
	    FreeFsPathInternalRep(objPtr);
	    objPtr->typePtr = NULL;
	    return Tcl_ConvertToType(interp, objPtr, &tclFsPathType);
	}
	return TCL_OK;
	/* 
	 * This code is intentionally never reached.  Once fs-optimisation
	 * is complete, it will be removed/replaced
	 */
#if 0

	if (fsPathPtr->cwdPtr == NULL) {
	    return TCL_OK;
	} else {
	    if (TclFSCwdPointerEquals(fsPathPtr->cwdPtr)) {
		return TCL_OK;
	    } else {
		if (objPtr->bytes == NULL) {
		    UpdateStringOfFsPath(objPtr);
		}

		FreeFsPathInternalRep(objPtr);
		objPtr->typePtr = NULL;







		return Tcl_ConvertToType(interp, objPtr, &tclFsPathType);
	    }
	}
#endif





    } else {


	return Tcl_ConvertToType(interp, objPtr, &tclFsPathType);
    }












}

/* 
 * Helper function for SetFsPathFromAny.  Returns position of first
 * directory delimiter in the path.

 */
static int
FindSplitPos(path, separator)
    char *path;
    char *separator;
{
    int count = 0;
    switch (tclPlatform) {
	case TCL_PLATFORM_UNIX:
	case TCL_PLATFORM_MAC:
	    while (path[count] != 0) {
		if (path[count] == *separator) {
		    return count;
		}
		count++;
	    }
	    break;

	case TCL_PLATFORM_WINDOWS:
	    while (path[count] != 0) {
		if (path[count] == *separator || path[count] == '\\') {
		    return count;
		}
		count++;
	    }
	    break;
    }
    return count;
}

/*
 *---------------------------------------------------------------------------
 *
 * TclNewFSPathObj --
 *
 *      Creates a path object whose string representation is 
 *      '[file join dirPtr addStrRep]', but does so in a way that
 *      allows for more efficient caching of normalized paths.

 *      
 * Assumptions:
 *      'dirPtr' must be an absolute path.  
 *      'len' may not be zero.
 *      
 * Results:
 *      The new Tcl object, with refCount zero.
 *
 * Side effects:
 *	Memory is allocated.  'dirPtr' gets an additional refCount.
 *
 *---------------------------------------------------------------------------
 */

Tcl_Obj*
TclNewFSPathObj(Tcl_Obj *dirPtr, CONST char *addStrRep, int len)
{
    FsPath *fsPathPtr;
    Tcl_Obj *objPtr;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
    


    objPtr = Tcl_NewObj();
    fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath));
    
    if (tclPlatform == TCL_PLATFORM_MAC) { 
	/* 
	 * Mac relative paths may begin with a directory separator ':'. 
	 * If present, we need to skip this ':' because we assume that 
	 * we can join dirPtr and addStrRep by concatenating them as 
	 * strings (and we ensure that dirPtr is terminated by a ':'). 
	 */ 
	if (addStrRep[0] == ':') { 
	    addStrRep++; 
	    len--; 
	} 
    } 
    /* Setup the path */
    fsPathPtr->translatedPathPtr = NULL;
    fsPathPtr->normPathPtr = Tcl_NewStringObj(addStrRep, len);
    Tcl_IncrRefCount(fsPathPtr->normPathPtr);
    fsPathPtr->cwdPtr = dirPtr;
    Tcl_IncrRefCount(dirPtr);
    fsPathPtr->nativePathPtr = NULL;
    fsPathPtr->fsRecPtr = NULL;
    fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;

    PATHOBJ(objPtr) = (VOID *) fsPathPtr;
    PATHFLAGS(objPtr) = TCLPATH_RELATIVE | TCLPATH_APPENDED;
    objPtr->typePtr = &tclFsPathType;
    objPtr->bytes = NULL;
    objPtr->length = 0;

    return objPtr;
}

/*
 *---------------------------------------------------------------------------
 *
 * TclFSMakePathRelative --
 *
 *      Like SetFsPathFromAny, but assumes the given object is an
 *      absolute normalized path. Only for internal use.
 *      





 * Results:


 *      Standard Tcl error code.
 *
 * Side effects:
 *	The old representation may be freed, and new memory allocated.
 *
 *---------------------------------------------------------------------------
 */

Tcl_Obj*
TclFSMakePathRelative(interp, objPtr, cwdPtr)
    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */
    Tcl_Obj *objPtr;		/* The object we have. */
    Tcl_Obj *cwdPtr;		/* Make it relative to this. */
{
    int cwdLen, len;
    CONST char *tempStr;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
    
    if (objPtr->typePtr == &tclFsPathType) {
	FsPath* fsPathPtr = (FsPath*) PATHOBJ(objPtr);
	if (PATHFLAGS(objPtr) != 0 
		&& fsPathPtr->cwdPtr == cwdPtr) {
	    objPtr = fsPathPtr->normPathPtr;
	    /* Free old representation */
	    if (objPtr->typePtr != NULL) {
		if (objPtr->bytes == NULL) {
		    if (objPtr->typePtr->updateStringProc == NULL) {
			if (interp != NULL) {
			    Tcl_ResetResult(interp);
			    Tcl_AppendResult(interp, "can't find object",
					     "string representation", (char *) NULL);
			}
			return NULL;
		    }
		    objPtr->typePtr->updateStringProc(objPtr);
		}
		if ((objPtr->typePtr->freeIntRepProc) != NULL) {
		    (*objPtr->typePtr->freeIntRepProc)(objPtr);
		}
	    }

	    fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath));

	    /* Circular reference, by design */
	    fsPathPtr->translatedPathPtr = objPtr;
	    fsPathPtr->normPathPtr = NULL;
	    fsPathPtr->cwdPtr = cwdPtr;
	    Tcl_IncrRefCount(cwdPtr);
	    fsPathPtr->nativePathPtr = NULL;
	    fsPathPtr->fsRecPtr = NULL;
	    fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;

	    PATHOBJ(objPtr) = (VOID *) fsPathPtr;
	    PATHFLAGS(objPtr) = 0;
	    objPtr->typePtr = &tclFsPathType;

	    return objPtr;
	}
    }
    /* 
     * We know the cwd is a normalised object which does
     * not end in a directory delimiter, unless the cwd
     * is the name of a volume, in which case it will
     * end in a delimiter!  We handle this situation here.







|


|













|
|

|
|

|
|
|



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

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




|
>



|
|






|








|














|
|
|
>


















|
|

>
>
|













|










|
|
|
|
|

|







<
|

>
>
>
>
>

>
>
|








|

|






|
|
|

|

|
|
|



|



|

|
|






|







|
|
|

|







965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000

1001


1002
1003
1004
1005
1006
1007
1008
1009
1010

1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153

1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
 *
 * Side effects:
 *	The old representation may be freed, and new memory allocated.
 *
 *---------------------------------------------------------------------------
 */
int 
Tcl_FSConvertToPathType(interp, pathPtr)
    Tcl_Interp *interp;		/* Interpreter in which to store error
				 * message (if necessary). */
    Tcl_Obj *pathPtr;		/* Object to convert to a valid, current
				 * path type. */
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);

    /* 
     * While it is bad practice to examine an object's type directly,
     * this is actually the best thing to do here.  The reason is that
     * if we are converting this object to FsPath type for the first
     * time, we don't need to worry whether the 'cwd' has changed.
     * On the other hand, if this object is already of FsPath type,
     * and is a relative path, we do have to worry about the cwd.
     * If the cwd has changed, we must recompute the path.
     */
    if (pathPtr->typePtr == &tclFsPathType) {
	FsPath *fsPathPtr = (FsPath*) PATHOBJ(pathPtr);
	if (fsPathPtr->filesystemEpoch != tsdPtr->filesystemEpoch) {
	    if (pathPtr->bytes == NULL) {
		UpdateStringOfFsPath(pathPtr);
	    }
	    FreeFsPathInternalRep(pathPtr);
	    pathPtr->typePtr = NULL;
	    return Tcl_ConvertToType(interp, pathPtr, &tclFsPathType);
	}
	return TCL_OK;
	/* 

	 * We used to have more complex code here:


	 * 
	 * 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.
	 */
    } else {
	return Tcl_ConvertToType(interp, pathPtr, &tclFsPathType);
    }
}

/* 
 * Helper function for normalization.
 */
static int
IsSeparatorOrNull(ch)
    int ch;
{
    if (ch == 0) {
        return 1;
    }
    switch (tclPlatform) {
	case TCL_PLATFORM_UNIX: {
	    return (ch == '/' ? 1 : 0);
	}
	case TCL_PLATFORM_MAC: {
	    return (ch == ':' ? 1 : 0);
	}
	case TCL_PLATFORM_WINDOWS: {
	    return ((ch == '/' || ch == '\\') ? 1 : 0);
	}
    }
    return 0;
}

/* 
 * Helper function for SetFsPathFromAny.  Returns position of first
 * directory delimiter in the path.  If no separator is found, then
 * returns the position of the end of the string.
 */
static int
FindSplitPos(path, separator)
    CONST char *path;
    int separator;
{
    int count = 0;
    switch (tclPlatform) {
	case TCL_PLATFORM_UNIX:
	case TCL_PLATFORM_MAC:
	    while (path[count] != 0) {
		if (path[count] == separator) {
		    return count;
		}
		count++;
	    }
	    break;

	case TCL_PLATFORM_WINDOWS:
	    while (path[count] != 0) {
		if (path[count] == separator || path[count] == '\\') {
		    return count;
		}
		count++;
	    }
	    break;
    }
    return count;
}

/*
 *---------------------------------------------------------------------------
 *
 * TclNewFSPathObj --
 *
 *      Creates a path object whose string representation is '[file join
 *      dirPtr addStrRep]', but does so in a way that allows for more
 *      efficient creation and caching of normalized paths, and more
 *      efficient 'file dirname', 'file tail', etc.
 *      
 * Assumptions:
 *      'dirPtr' must be an absolute path.  
 *      'len' may not be zero.
 *      
 * Results:
 *      The new Tcl object, with refCount zero.
 *
 * Side effects:
 *	Memory is allocated.  'dirPtr' gets an additional refCount.
 *
 *---------------------------------------------------------------------------
 */

Tcl_Obj*
TclNewFSPathObj(Tcl_Obj *dirPtr, CONST char *addStrRep, int len)
{
    FsPath *fsPathPtr;
    Tcl_Obj *pathPtr;
    ThreadSpecificData *tsdPtr;
    
    tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
    
    pathPtr = Tcl_NewObj();
    fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath));
    
    if (tclPlatform == TCL_PLATFORM_MAC) { 
	/* 
	 * Mac relative paths may begin with a directory separator ':'. 
	 * If present, we need to skip this ':' because we assume that 
	 * we can join dirPtr and addStrRep by concatenating them as 
	 * strings (and we ensure that dirPtr is terminated by a ':'). 
	 */ 
	if (addStrRep[0] == ':') { 
	    addStrRep++; 
	    len--; 
	} 
    }
    /* Setup the path */
    fsPathPtr->translatedPathPtr = NULL;
    fsPathPtr->normPathPtr = Tcl_NewStringObj(addStrRep, len);
    Tcl_IncrRefCount(fsPathPtr->normPathPtr);
    fsPathPtr->cwdPtr = dirPtr;
    Tcl_IncrRefCount(dirPtr);
    fsPathPtr->nativePathPtr = NULL;
    fsPathPtr->fsRecPtr = NULL;
    fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;

    PATHOBJ(pathPtr) = (VOID *) fsPathPtr;
    PATHFLAGS(pathPtr) = TCLPATH_APPENDED;
    pathPtr->typePtr = &tclFsPathType;
    pathPtr->bytes = NULL;
    pathPtr->length = 0;

    return pathPtr;
}

/*
 *---------------------------------------------------------------------------
 *
 * TclFSMakePathRelative --
 *

 *      Only for internal use.
 *      
 *      Takes a path and a directory, where we _assume_ both path and
 *      directory are absolute, normalized and that the path lies
 *      inside the directory.  Returns a Tcl_Obj representing filename 
 *      of the path relative to the directory.
 *      
 * Results:
 *      NULL on error, otherwise a valid object, typically with
 *      refCount of zero, which it is assumed the caller will
 *      increment.
 *
 * Side effects:
 *	The old representation may be freed, and new memory allocated.
 *
 *---------------------------------------------------------------------------
 */

Tcl_Obj*
TclFSMakePathRelative(interp, pathPtr, cwdPtr)
    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */
    Tcl_Obj *pathPtr;		/* The object we have. */
    Tcl_Obj *cwdPtr;		/* Make it relative to this. */
{
    int cwdLen, len;
    CONST char *tempStr;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
    
    if (pathPtr->typePtr == &tclFsPathType) {
	FsPath* fsPathPtr = (FsPath*) PATHOBJ(pathPtr);
	if (PATHFLAGS(pathPtr) != 0 
		&& fsPathPtr->cwdPtr == cwdPtr) {
	    pathPtr = fsPathPtr->normPathPtr;
	    /* Free old representation */
	    if (pathPtr->typePtr != NULL) {
		if (pathPtr->bytes == NULL) {
		    if (pathPtr->typePtr->updateStringProc == NULL) {
			if (interp != NULL) {
			    Tcl_ResetResult(interp);
			    Tcl_AppendResult(interp, "can't find object",
				   "string representation", (char *) NULL);
			}
			return NULL;
		    }
		    pathPtr->typePtr->updateStringProc(pathPtr);
		}
		if ((pathPtr->typePtr->freeIntRepProc) != NULL) {
		    (*pathPtr->typePtr->freeIntRepProc)(pathPtr);
		}
	    }

	    fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath));

	    /* Circular reference, by design */
	    fsPathPtr->translatedPathPtr = pathPtr;
	    fsPathPtr->normPathPtr = NULL;
	    fsPathPtr->cwdPtr = cwdPtr;
	    Tcl_IncrRefCount(cwdPtr);
	    fsPathPtr->nativePathPtr = NULL;
	    fsPathPtr->fsRecPtr = NULL;
	    fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;

	    PATHOBJ(pathPtr) = (VOID *) fsPathPtr;
	    PATHFLAGS(pathPtr) = 0;
	    pathPtr->typePtr = &tclFsPathType;

	    return pathPtr;
	}
    }
    /* 
     * We know the cwd is a normalised object which does
     * not end in a directory delimiter, unless the cwd
     * is the name of a volume, in which case it will
     * end in a delimiter!  We handle this situation here.
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
	    break;
	case TCL_PLATFORM_MAC:
	    if (tempStr[cwdLen-1] != ':') {
		cwdLen++;
	    }
	    break;
    }
    tempStr = Tcl_GetStringFromObj(objPtr, &len);

    return Tcl_NewStringObj(tempStr + cwdLen, len - cwdLen);
}

/*
 *---------------------------------------------------------------------------
 *







|







1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
	    break;
	case TCL_PLATFORM_MAC:
	    if (tempStr[cwdLen-1] != ':') {
		cwdLen++;
	    }
	    break;
    }
    tempStr = Tcl_GetStringFromObj(pathPtr, &len);

    return Tcl_NewStringObj(tempStr + cwdLen, len - cwdLen);
}

/*
 *---------------------------------------------------------------------------
 *
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
 * Side effects:
 *	The old representation may be freed, and new memory allocated.
 *
 *---------------------------------------------------------------------------
 */

int
TclFSMakePathFromNormalized(interp, objPtr, nativeRep)
    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */
    Tcl_Obj *objPtr;		/* The object to convert. */
    ClientData nativeRep;	/* The native rep for the object, if known
				 * else NULL. */
{
    FsPath *fsPathPtr;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);

    if (objPtr->typePtr == &tclFsPathType) {
	return TCL_OK;
    }
    
    /* Free old representation */
    if (objPtr->typePtr != NULL) {
	if (objPtr->bytes == NULL) {
	    if (objPtr->typePtr->updateStringProc == NULL) {
		if (interp != NULL) {
		    Tcl_ResetResult(interp);
		    Tcl_AppendResult(interp, "can't find object",
				     "string representation", (char *) NULL);
		}
		return TCL_ERROR;
	    }
	    objPtr->typePtr->updateStringProc(objPtr);
	}
	if ((objPtr->typePtr->freeIntRepProc) != NULL) {
	    (*objPtr->typePtr->freeIntRepProc)(objPtr);
	}
    }

    fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath));
    /* It's a pure normalized absolute path */
    fsPathPtr->translatedPathPtr = NULL;

    fsPathPtr->normPathPtr = objPtr;
    fsPathPtr->cwdPtr = NULL;
    fsPathPtr->nativePathPtr = nativeRep;
    fsPathPtr->fsRecPtr = NULL;
    fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;

    PATHOBJ(objPtr) = (VOID *) fsPathPtr;
    PATHFLAGS(objPtr) = 0;
    objPtr->typePtr = &tclFsPathType;

    return TCL_OK;
}

/*
 *---------------------------------------------------------------------------
 *







|

|






|




|
|
|







|

|
|






>
|





|
|
|







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
 * Side effects:
 *	The old representation may be freed, and new memory allocated.
 *
 *---------------------------------------------------------------------------
 */

int
TclFSMakePathFromNormalized(interp, pathPtr, nativeRep)
    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */
    Tcl_Obj *pathPtr;		/* The object to convert. */
    ClientData nativeRep;	/* The native rep for the object, if known
				 * else NULL. */
{
    FsPath *fsPathPtr;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);

    if (pathPtr->typePtr == &tclFsPathType) {
	return TCL_OK;
    }
    
    /* Free old representation */
    if (pathPtr->typePtr != NULL) {
	if (pathPtr->bytes == NULL) {
	    if (pathPtr->typePtr->updateStringProc == NULL) {
		if (interp != NULL) {
		    Tcl_ResetResult(interp);
		    Tcl_AppendResult(interp, "can't find object",
				     "string representation", (char *) NULL);
		}
		return TCL_ERROR;
	    }
	    pathPtr->typePtr->updateStringProc(pathPtr);
	}
	if ((pathPtr->typePtr->freeIntRepProc) != NULL) {
	    (*pathPtr->typePtr->freeIntRepProc)(pathPtr);
	}
    }

    fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath));
    /* It's a pure normalized absolute path */
    fsPathPtr->translatedPathPtr = NULL;
    /* Circular reference by design */
    fsPathPtr->normPathPtr = pathPtr;
    fsPathPtr->cwdPtr = NULL;
    fsPathPtr->nativePathPtr = nativeRep;
    fsPathPtr->fsRecPtr = NULL;
    fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;

    PATHOBJ(pathPtr) = (VOID *) fsPathPtr;
    PATHFLAGS(pathPtr) = 0;
    pathPtr->typePtr = &tclFsPathType;

    return TCL_OK;
}

/*
 *---------------------------------------------------------------------------
 *
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
 */

Tcl_Obj *
Tcl_FSNewNativePath(fromFilesystem, clientData)
    Tcl_Filesystem* fromFilesystem;
    ClientData clientData;
{
    Tcl_Obj *objPtr;
    FsPath *fsPathPtr;

    FilesystemRecord *fsFromPtr;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
    
    objPtr = TclFSInternalToNormalized(fromFilesystem, clientData,
                                       &fsFromPtr);
    if (objPtr == NULL) {
	return NULL;
    }
    
    /* 
     * Free old representation; shouldn't normally be any,
     * but best to be safe. 
     */
    if (objPtr->typePtr != NULL) {
	if (objPtr->bytes == NULL) {
	    if (objPtr->typePtr->updateStringProc == NULL) {
		return NULL;
	    }
	    objPtr->typePtr->updateStringProc(objPtr);
	}
	if ((objPtr->typePtr->freeIntRepProc) != NULL) {
	    (*objPtr->typePtr->freeIntRepProc)(objPtr);
	}
    }
    
    fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath));

    fsPathPtr->translatedPathPtr = NULL;
    /* Circular reference, by design */
    fsPathPtr->normPathPtr = objPtr;
    fsPathPtr->cwdPtr = NULL;
    fsPathPtr->nativePathPtr = clientData;
    fsPathPtr->fsRecPtr = fsFromPtr;
    fsPathPtr->fsRecPtr->fileRefCount++;
    fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;  

    PATHOBJ(objPtr) = (VOID *) fsPathPtr;
    PATHFLAGS(objPtr) = 0;
    objPtr->typePtr = &tclFsPathType;

    return objPtr;
}

/*
 *---------------------------------------------------------------------------
 *
 * Tcl_FSGetTranslatedPath --
 *







|





|

|







|
|
|


|

|
|







|






|
|
|

|







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
 */

Tcl_Obj *
Tcl_FSNewNativePath(fromFilesystem, clientData)
    Tcl_Filesystem* fromFilesystem;
    ClientData clientData;
{
    Tcl_Obj *pathPtr;
    FsPath *fsPathPtr;

    FilesystemRecord *fsFromPtr;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
    
    pathPtr = TclFSInternalToNormalized(fromFilesystem, clientData,
                                       &fsFromPtr);
    if (pathPtr == NULL) {
	return NULL;
    }
    
    /* 
     * Free old representation; shouldn't normally be any,
     * but best to be safe. 
     */
    if (pathPtr->typePtr != NULL) {
	if (pathPtr->bytes == NULL) {
	    if (pathPtr->typePtr->updateStringProc == NULL) {
		return NULL;
	    }
	    pathPtr->typePtr->updateStringProc(pathPtr);
	}
	if ((pathPtr->typePtr->freeIntRepProc) != NULL) {
	    (*pathPtr->typePtr->freeIntRepProc)(pathPtr);
	}
    }
    
    fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath));

    fsPathPtr->translatedPathPtr = NULL;
    /* Circular reference, by design */
    fsPathPtr->normPathPtr = pathPtr;
    fsPathPtr->cwdPtr = NULL;
    fsPathPtr->nativePathPtr = clientData;
    fsPathPtr->fsRecPtr = fsFromPtr;
    fsPathPtr->fsRecPtr->fileRefCount++;
    fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;  

    PATHOBJ(pathPtr) = (VOID *) fsPathPtr;
    PATHFLAGS(pathPtr) = 0;
    pathPtr->typePtr = &tclFsPathType;

    return pathPtr;
}

/*
 *---------------------------------------------------------------------------
 *
 * Tcl_FSGetTranslatedPath --
 *
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967

968
969
970
971
972
973
974

    if (Tcl_FSConvertToPathType(interp, pathPtr) != TCL_OK) {
	return NULL;
    }
    srcFsPathPtr = (FsPath*) PATHOBJ(pathPtr);
    if (srcFsPathPtr->translatedPathPtr == NULL) {
	if (PATHFLAGS(pathPtr) != 0) {
	    return Tcl_FSGetNormalizedPath(interp, pathPtr);
	}
	/* 
	 * It is a pure absolute, normalized path object.
	 * This is something like being a 'pure list'.  The
	 * object's string, translatedPath and normalizedPath
	 * are all identical.
	 */
	retObj = srcFsPathPtr->normPathPtr;

    } else {
	/* It is an ordinary path object */
	retObj = srcFsPathPtr->translatedPathPtr;
    }

    Tcl_IncrRefCount(retObj);
    return retObj;







|
|
|
|
|
|
|
|
|
>







1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458

    if (Tcl_FSConvertToPathType(interp, pathPtr) != TCL_OK) {
	return NULL;
    }
    srcFsPathPtr = (FsPath*) PATHOBJ(pathPtr);
    if (srcFsPathPtr->translatedPathPtr == NULL) {
	if (PATHFLAGS(pathPtr) != 0) {
	    retObj = Tcl_FSGetNormalizedPath(interp, pathPtr);
	} else {
	    /* 
	     * It is a pure absolute, normalized path object.
	     * This is something like being a 'pure list'.  The
	     * object's string, translatedPath and normalizedPath
	     * are all identical.
	     */
	    retObj = srcFsPathPtr->normPathPtr;
	}
    } else {
	/* It is an ordinary path object */
	retObj = srcFsPathPtr->translatedPathPtr;
    }

    Tcl_IncrRefCount(retObj);
    return retObj;
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
 *	New memory may be allocated.  The Tcl 'errno' may be modified
 *      in the process of trying to examine various path possibilities.
 *
 *---------------------------------------------------------------------------
 */

Tcl_Obj* 
Tcl_FSGetNormalizedPath(interp, pathObjPtr)
    Tcl_Interp *interp;
    Tcl_Obj* pathObjPtr;
{

    FsPath *fsPathPtr;

    if (Tcl_FSConvertToPathType(interp, pathObjPtr) != TCL_OK) {
	return NULL;
    }
    fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr);

    if (PATHFLAGS(pathObjPtr) != 0) {
	/* 
	 * This is a special path object which is the result of
	 * something like 'file join' 
	 */
	Tcl_Obj *dir, *copy;
	int cwdLen;
	int pathType;
	CONST char *cwdStr;
	ClientData clientData = NULL;
	
	pathType = Tcl_FSGetPathType(fsPathPtr->cwdPtr);
	dir = Tcl_FSGetNormalizedPath(interp, fsPathPtr->cwdPtr);
	if (dir == NULL) {
	    return NULL;
	}
	if (pathObjPtr->bytes == NULL) {
	    UpdateStringOfFsPath(pathObjPtr);
	}
	copy = Tcl_DuplicateObj(dir);
	Tcl_IncrRefCount(copy);
	Tcl_IncrRefCount(dir);
	/* We now own a reference on both 'dir' and 'copy' */
	
	cwdStr = Tcl_GetStringFromObj(copy, &cwdLen);







|

|




|


|

|















|
|







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
 *	New memory may be allocated.  The Tcl 'errno' may be modified
 *      in the process of trying to examine various path possibilities.
 *
 *---------------------------------------------------------------------------
 */

Tcl_Obj* 
Tcl_FSGetNormalizedPath(interp, pathPtr)
    Tcl_Interp *interp;
    Tcl_Obj* pathPtr;
{

    FsPath *fsPathPtr;

    if (Tcl_FSConvertToPathType(interp, pathPtr) != TCL_OK) {
	return NULL;
    }
    fsPathPtr = (FsPath*) PATHOBJ(pathPtr);

    if (PATHFLAGS(pathPtr) != 0) {
	/* 
	 * This is a special path object which is the result of
	 * something like 'file join' 
	 */
	Tcl_Obj *dir, *copy;
	int cwdLen;
	int pathType;
	CONST char *cwdStr;
	ClientData clientData = NULL;
	
	pathType = Tcl_FSGetPathType(fsPathPtr->cwdPtr);
	dir = Tcl_FSGetNormalizedPath(interp, fsPathPtr->cwdPtr);
	if (dir == NULL) {
	    return NULL;
	}
	if (pathPtr->bytes == NULL) {
	    UpdateStringOfFsPath(pathPtr);
	}
	copy = Tcl_DuplicateObj(dir);
	Tcl_IncrRefCount(copy);
	Tcl_IncrRefCount(dir);
	/* We now own a reference on both 'dir' and 'copy' */
	
	cwdStr = Tcl_GetStringFromObj(copy, &cwdLen);
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
	    fsPathPtr->normPathPtr = copy;
	    /* That's our reference to copy used */
	    Tcl_DecrRefCount(dir);
	}
	if (clientData != NULL) {
	    fsPathPtr->nativePathPtr = clientData;
	}
	PATHFLAGS(pathObjPtr) = 0;
    }
    /* Ensure cwd hasn't changed */
    if (fsPathPtr->cwdPtr != NULL) {
	if (!TclFSCwdPointerEquals(fsPathPtr->cwdPtr)) {
	    if (pathObjPtr->bytes == NULL) {
		UpdateStringOfFsPath(pathObjPtr);
	    }
	    FreeFsPathInternalRep(pathObjPtr);
	    pathObjPtr->typePtr = NULL;
	    if (Tcl_ConvertToType(interp, pathObjPtr, 
				  &tclFsPathType) != TCL_OK) {
		return NULL;
	    }
	    fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr);
	} else if (fsPathPtr->normPathPtr == NULL) {
	    int cwdLen;
	    Tcl_Obj *copy;
	    CONST char *cwdStr;
	    ClientData clientData = NULL;
	    
	    copy = Tcl_DuplicateObj(fsPathPtr->cwdPtr);







|



|
|
|

|
|
|



|







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
	    fsPathPtr->normPathPtr = copy;
	    /* That's our reference to copy used */
	    Tcl_DecrRefCount(dir);
	}
	if (clientData != NULL) {
	    fsPathPtr->nativePathPtr = clientData;
	}
	PATHFLAGS(pathPtr) = 0;
    }
    /* Ensure cwd hasn't changed */
    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 = (FsPath*) PATHOBJ(pathPtr);
	} else if (fsPathPtr->normPathPtr == NULL) {
	    int cwdLen;
	    Tcl_Obj *copy;
	    CONST char *cwdStr;
	    ClientData clientData = NULL;
	    
	    copy = Tcl_DuplicateObj(fsPathPtr->cwdPtr);
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
		case TCL_PLATFORM_MAC:
		    if (cwdStr[cwdLen-1] != ':') {
			Tcl_AppendToObj(copy, ":", 1);
			cwdLen++;
		    }
		    break;
	    }
	    Tcl_AppendObjToObj(copy, pathObjPtr);
	    /* 
	     * Normalize the combined string, but only starting after
	     * the end of the previously normalized 'dir'.  This should
	     * be much faster!
	     */
	    TclFSNormalizeToUniquePath(interp, copy, cwdLen-1, 
	      (fsPathPtr->nativePathPtr == NULL ? &clientData : NULL));







|







1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
		case TCL_PLATFORM_MAC:
		    if (cwdStr[cwdLen-1] != ':') {
			Tcl_AppendToObj(copy, ":", 1);
			cwdLen++;
		    }
		    break;
	    }
	    Tcl_AppendObjToObj(copy, pathPtr);
	    /* 
	     * Normalize the combined string, but only starting after
	     * the end of the previously normalized 'dir'.  This should
	     * be much faster!
	     */
	    TclFSNormalizeToUniquePath(interp, copy, cwdLen-1, 
	      (fsPathPtr->nativePathPtr == NULL ? &clientData : NULL));
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
	/* 
	 * We have to be a little bit careful here to avoid infinite loops
	 * we're asking Tcl_FSGetPathType to return the path's type, but
	 * that call can actually result in a lot of other filesystem
	 * action, which might loop back through here.
	 */
	if (path[0] != '\0') {
	    Tcl_PathType type = Tcl_FSGetPathType(pathObjPtr);
	    if (type == TCL_PATH_RELATIVE) {
		useThisCwd = Tcl_FSGetCwd(interp);

		if (useThisCwd == NULL) return NULL;

		absolutePath = Tcl_FSJoinToPath(useThisCwd, 1, &absolutePath);
		Tcl_IncrRefCount(absolutePath);







|







1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
	/* 
	 * We have to be a little bit careful here to avoid infinite loops
	 * we're asking Tcl_FSGetPathType to return the path's type, but
	 * that call can actually result in a lot of other filesystem
	 * action, which might loop back through here.
	 */
	if (path[0] != '\0') {
	    Tcl_PathType type = Tcl_FSGetPathType(pathPtr);
	    if (type == TCL_PATH_RELATIVE) {
		useThisCwd = Tcl_FSGetCwd(interp);

		if (useThisCwd == NULL) return NULL;

		absolutePath = Tcl_FSJoinToPath(useThisCwd, 1, &absolutePath);
		Tcl_IncrRefCount(absolutePath);
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
		    Tcl_IncrRefCount(absolutePath);
		    /* We have a refCount on the cwd */
		} else {
		    /* 
		     * Path of form C:foo/bar, but this only makes
		     * sense if the cwd is also on drive C.
		     */

		    CONST char *drive = Tcl_GetString(useThisCwd);

		    char drive_c = path[0];
		    if (drive_c >= 'a') {
			drive_c -= ('a' - 'A');
		    }
		    if (drive[0] == drive_c) {
			absolutePath = Tcl_DuplicateObj(useThisCwd);
			Tcl_IncrRefCount(absolutePath);
			Tcl_AppendToObj(absolutePath, "/", 1);
			Tcl_AppendToObj(absolutePath, path+2, -1);
			/* We have a refCount on the cwd */
		    } else {
			/* We just can't handle it correctly here */
			Tcl_DecrRefCount(useThisCwd);
			useThisCwd = NULL;








		    }






		}
#endif /* __WIN32__ */
	    }
	}
	/* Already has refCount incremented */
	fsPathPtr->normPathPtr = TclFSNormalizeAbsolutePath(interp, absolutePath, 
		       (fsPathPtr->nativePathPtr == NULL ? &clientData : NULL));
	if (0 && (clientData != NULL)) {
	    fsPathPtr->nativePathPtr = 
	      (*fsPathPtr->fsRecPtr->fsPtr->dupInternalRepProc)(clientData);
	}





	if (!strcmp(Tcl_GetString(fsPathPtr->normPathPtr),
		    Tcl_GetString(pathObjPtr))) {
	    /* 
	     * The path was already normalized.  
	     * Get rid of the duplicate.
	     */
	    Tcl_DecrRefCount(fsPathPtr->normPathPtr);
	    /* 
	     * We do *not* increment the refCount for 
	     * this circular reference 
	     */
	    fsPathPtr->normPathPtr = pathObjPtr;
	}
	if (useThisCwd != NULL) {


	    /* This was returned by Tcl_FSJoinToPath above */


	    Tcl_DecrRefCount(absolutePath);
	    fsPathPtr->cwdPtr = useThisCwd;
	}
    }

    return fsPathPtr->normPathPtr;
}







>
|
>
|
|
|

|

<
<
<


<


>
>
>
>
>
>
>
>

>
>
>
>
>
>











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







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
		    Tcl_IncrRefCount(absolutePath);
		    /* We have a refCount on the cwd */
		} else {
		    /* 
		     * Path of form C:foo/bar, but this only makes
		     * sense if the cwd is also on drive C.
		     */
		    int cwdLen;
		    CONST char *drive = Tcl_GetStringFromObj(useThisCwd, 
							     &cwdLen);
		    char drive_cur = path[0];
		    if (drive_cur >= 'a') {
			drive_cur -= ('a' - 'A');
		    }
		    if (drive[0] == drive_cur) {
			absolutePath = Tcl_DuplicateObj(useThisCwd);



			/* We have a refCount on the cwd */
		    } else {

			Tcl_DecrRefCount(useThisCwd);
			useThisCwd = NULL;
			/* 
			 * The path is not in the current drive, but
			 * is volume-relative.  The way Tcl 8.3 handles
			 * this is that it treats such a path as
			 * relative to the root of the drive.  We
			 * therefore behave the same here.
			 */
			absolutePath = Tcl_NewStringObj(path, 2);
		    }
		    Tcl_IncrRefCount(absolutePath);
		    if (drive[cwdLen-1] != '/') {
			/* Only add a trailing '/' if needed */
		        Tcl_AppendToObj(absolutePath, "/", 1);
		    }
		    Tcl_AppendToObj(absolutePath, path+2, -1);
		}
#endif /* __WIN32__ */
	    }
	}
	/* Already has refCount incremented */
	fsPathPtr->normPathPtr = TclFSNormalizeAbsolutePath(interp, absolutePath, 
		       (fsPathPtr->nativePathPtr == NULL ? &clientData : NULL));
	if (0 && (clientData != NULL)) {
	    fsPathPtr->nativePathPtr = 
	      (*fsPathPtr->fsRecPtr->fsPtr->dupInternalRepProc)(clientData);
	}
	/* 
	 * Check if path is pure normalized (this can only be the case
	 * if it is an absolute path).
	 */
	if (useThisCwd == NULL) {
	    if (!strcmp(Tcl_GetString(fsPathPtr->normPathPtr),
			Tcl_GetString(pathPtr))) {
		/* 
		 * The path was already normalized.  
		 * Get rid of the duplicate.
		 */
		Tcl_DecrRefCount(fsPathPtr->normPathPtr);
		/* 
		 * We do *not* increment the refCount for 
		 * this circular reference 
		 */
		fsPathPtr->normPathPtr = pathPtr;
	    }
	} else {
	    /* 
	     * We just need to free an object we allocated above for
	     * relative paths (this was returned by Tcl_FSJoinToPath
	     * above), and then of course store the cwd.
	     */
	    Tcl_DecrRefCount(absolutePath);
	    fsPathPtr->cwdPtr = useThisCwd;
	}
    }

    return fsPathPtr->normPathPtr;
}
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
 * Side effects:
 *	An attempt may be made to convert the object.
 *
 *---------------------------------------------------------------------------
 */

ClientData 
Tcl_FSGetInternalRep(pathObjPtr, fsPtr)
    Tcl_Obj* pathObjPtr;
    Tcl_Filesystem *fsPtr;
{
    FsPath* srcFsPathPtr;
    
    if (Tcl_FSConvertToPathType(NULL, pathObjPtr) != TCL_OK) {
	return NULL;
    }
    srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr);
    
    /* 
     * We will only return the native representation for the caller's
     * filesystem.  Otherwise we will simply return NULL. This means
     * that there must be a unique bi-directional mapping between paths
     * and filesystems, and that this mapping will not allow 'remapped'
     * files -- files which are in one filesystem but mapped into







|
|




|


|







1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
 * Side effects:
 *	An attempt may be made to convert the object.
 *
 *---------------------------------------------------------------------------
 */

ClientData 
Tcl_FSGetInternalRep(pathPtr, fsPtr)
    Tcl_Obj* pathPtr;
    Tcl_Filesystem *fsPtr;
{
    FsPath* srcFsPathPtr;
    
    if (Tcl_FSConvertToPathType(NULL, pathPtr) != TCL_OK) {
	return NULL;
    }
    srcFsPathPtr = (FsPath*) PATHOBJ(pathPtr);
    
    /* 
     * We will only return the native representation for the caller's
     * filesystem.  Otherwise we will simply return NULL. This means
     * that there must be a unique bi-directional mapping between paths
     * and filesystems, and that this mapping will not allow 'remapped'
     * files -- files which are in one filesystem but mapped into
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
	 * create a string object and pass it to TclpObjStat.  Code
	 * which calls the Tcl_FS..  functions should always have a
	 * filesystem already set.  Whether this code path is legal or
	 * not depends on whether we decide to allow external code to
	 * call the native filesystem directly.  It is at least safer
	 * to allow this sub-optimal routing.
	 */
	Tcl_FSGetFileSystemForPath(pathObjPtr);
	
	/* 
	 * If we fail through here, then the path is probably not a
	 * valid path in the filesystsem, and is most likely to be a
	 * use of the empty path "" via a direct call to one of the
	 * objectified interfaces (e.g. from the Tcl testsuite).
	 */
	srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr);
	if (srcFsPathPtr->fsRecPtr == NULL) {
	    return NULL;
	}
    }

    if (fsPtr != srcFsPathPtr->fsRecPtr->fsPtr) {
	/* 
	 * There is still one possibility we should consider; if the
	 * file belongs to a different filesystem, perhaps it is
	 * actually linked through to a file in our own filesystem
	 * which we do care about.  The way we can check for this
	 * is we ask what filesystem this path belongs to.
	 */
	Tcl_Filesystem *actualFs = Tcl_FSGetFileSystemForPath(pathObjPtr);
	if (actualFs == fsPtr) {
	    return Tcl_FSGetInternalRep(pathObjPtr, fsPtr);
	}
	return NULL;
    }

    if (srcFsPathPtr->nativePathPtr == NULL) {
	Tcl_FSCreateInternalRepProc *proc;
	proc = srcFsPathPtr->fsRecPtr->fsPtr->createInternalRepProc;

	if (proc == NULL) {
	    return NULL;
	}
	srcFsPathPtr->nativePathPtr = (*proc)(pathObjPtr);
    }

    return srcFsPathPtr->nativePathPtr;
}

/*
 *---------------------------------------------------------------------------
 *
 * TclFSEnsureEpochOk --
 *
 *      This will ensure the pathObjPtr is up to date and can be
 *      converted into a "path" type, and that we are able to generate a
 *      complete normalized path which is used to determine the
 *      filesystem match.
 *
 * Results:
 *      Standard Tcl return code.
 *
 * Side effects:
 *	An attempt may be made to convert the object.
 *
 *---------------------------------------------------------------------------
 */

int 
TclFSEnsureEpochOk(pathObjPtr, fsPtrPtr)
    Tcl_Obj* pathObjPtr;
    Tcl_Filesystem **fsPtrPtr;
{
    FsPath* srcFsPathPtr;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);

    /* 
     * SHOULD BE ABLE TO IMPROVE EFFICIENCY HERE.
     */

    if (Tcl_FSGetNormalizedPath(NULL, pathObjPtr) == NULL) {
	return TCL_ERROR;
    }

    srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr);

    /* 
     * Check if the filesystem has changed in some way since
     * this object's internal representation was calculated.
     */
    if (srcFsPathPtr->filesystemEpoch != tsdPtr->filesystemEpoch) {
	/* 
	 * We have to discard the stale representation and 
	 * recalculate it 
	 */
	if (pathObjPtr->bytes == NULL) {
	    UpdateStringOfFsPath(pathObjPtr);
	}
	FreeFsPathInternalRep(pathObjPtr);
	pathObjPtr->typePtr = NULL;
	if (SetFsPathFromAny(NULL, pathObjPtr) != TCL_OK) {
	    return TCL_ERROR;
	}
	srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr);
    }
    /* Check whether the object is already assigned to a fs */
    if (srcFsPathPtr->fsRecPtr != NULL) {
	*fsPtrPtr = srcFsPathPtr->fsRecPtr->fsPtr;
    }

    return TCL_OK;
}

void 
TclFSSetPathDetails(pathObjPtr, fsRecPtr, clientData) 
    Tcl_Obj *pathObjPtr;
    FilesystemRecord *fsRecPtr;
    ClientData clientData;
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
    /* We assume pathObjPtr is already of the correct type */
    FsPath* srcFsPathPtr;
    







    srcFsPathPtr = (FsPath*) PATHOBJ(pathObjPtr);
    srcFsPathPtr->fsRecPtr = fsRecPtr;
    srcFsPathPtr->nativePathPtr = clientData;
    srcFsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; 
    fsRecPtr->fileRefCount++;
}

/*







|







|













|

|











|










|














|
|





<
<
<
|
<
|


|










|
|

|
|
|


|










|
|




<


>
>
>
>
>
>
>
|







1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944



1945

1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984

1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
	 * create a string object and pass it to TclpObjStat.  Code
	 * which calls the Tcl_FS..  functions should always have a
	 * filesystem already set.  Whether this code path is legal or
	 * not depends on whether we decide to allow external code to
	 * call the native filesystem directly.  It is at least safer
	 * to allow this sub-optimal routing.
	 */
	Tcl_FSGetFileSystemForPath(pathPtr);
	
	/* 
	 * If we fail through here, then the path is probably not a
	 * valid path in the filesystsem, and is most likely to be a
	 * use of the empty path "" via a direct call to one of the
	 * objectified interfaces (e.g. from the Tcl testsuite).
	 */
	srcFsPathPtr = (FsPath*) PATHOBJ(pathPtr);
	if (srcFsPathPtr->fsRecPtr == NULL) {
	    return NULL;
	}
    }

    if (fsPtr != srcFsPathPtr->fsRecPtr->fsPtr) {
	/* 
	 * There is still one possibility we should consider; if the
	 * file belongs to a different filesystem, perhaps it is
	 * actually linked through to a file in our own filesystem
	 * which we do care about.  The way we can check for this
	 * is we ask what filesystem this path belongs to.
	 */
	Tcl_Filesystem *actualFs = Tcl_FSGetFileSystemForPath(pathPtr);
	if (actualFs == fsPtr) {
	    return Tcl_FSGetInternalRep(pathPtr, fsPtr);
	}
	return NULL;
    }

    if (srcFsPathPtr->nativePathPtr == NULL) {
	Tcl_FSCreateInternalRepProc *proc;
	proc = srcFsPathPtr->fsRecPtr->fsPtr->createInternalRepProc;

	if (proc == NULL) {
	    return NULL;
	}
	srcFsPathPtr->nativePathPtr = (*proc)(pathPtr);
    }

    return srcFsPathPtr->nativePathPtr;
}

/*
 *---------------------------------------------------------------------------
 *
 * TclFSEnsureEpochOk --
 *
 *      This will ensure the pathPtr is up to date and can be
 *      converted into a "path" type, and that we are able to generate a
 *      complete normalized path which is used to determine the
 *      filesystem match.
 *
 * Results:
 *      Standard Tcl return code.
 *
 * Side effects:
 *	An attempt may be made to convert the object.
 *
 *---------------------------------------------------------------------------
 */

int 
TclFSEnsureEpochOk(pathPtr, fsPtrPtr)
    Tcl_Obj* pathPtr;
    Tcl_Filesystem **fsPtrPtr;
{
    FsPath* srcFsPathPtr;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);




    if (pathPtr->typePtr != &tclFsPathType) {

	return TCL_OK;
    }

    srcFsPathPtr = (FsPath*) PATHOBJ(pathPtr);

    /* 
     * Check if the filesystem has changed in some way since
     * this object's internal representation was calculated.
     */
    if (srcFsPathPtr->filesystemEpoch != tsdPtr->filesystemEpoch) {
	/* 
	 * 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 = (FsPath*) PATHOBJ(pathPtr);
    }
    /* Check whether the object is already assigned to a fs */
    if (srcFsPathPtr->fsRecPtr != NULL) {
	*fsPtrPtr = srcFsPathPtr->fsRecPtr->fsPtr;
    }

    return TCL_OK;
}

void 
TclFSSetPathDetails(pathPtr, fsRecPtr, clientData) 
    Tcl_Obj *pathPtr;
    FilesystemRecord *fsRecPtr;
    ClientData clientData;
{
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);

    FsPath* srcFsPathPtr;
    
    /* Make sure pathPtr is of the correct type */
    if (pathPtr->typePtr != &tclFsPathType) {
	if (SetFsPathFromAny(NULL, pathPtr) != TCL_OK) {
	    return;
	}
    }
    
    srcFsPathPtr = (FsPath*) PATHOBJ(pathPtr);
    srcFsPathPtr->fsRecPtr = fsRecPtr;
    srcFsPathPtr->nativePathPtr = clientData;
    srcFsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch; 
    fsRecPtr->fileRefCount++;
}

/*
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
 * Side effects:
 *	The old representation may be freed, and new memory allocated.
 *
 *---------------------------------------------------------------------------
 */

static int
SetFsPathFromAny(interp, objPtr)
    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */
    Tcl_Obj *objPtr;		/* The object to convert. */
{
    int len;
    FsPath *fsPathPtr;
    Tcl_Obj *transPtr;
    char *name;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
    
    if (objPtr->typePtr == &tclFsPathType) {
	return TCL_OK;
    }
    
    /* 
     * First step is to translate the filename.  This is similar to
     * Tcl_TranslateFilename, but shouldn't convert everything to
     * windows backslashes on that platform.  The current
     * implementation of this piece is a slightly optimised version
     * of the various Tilde/Split/Join stuff to avoid multiple
     * split/join operations.
     * 
     * We remove any trailing directory separator.
     * 
     * However, the split/join routines are quite complex, and
     * one has to make sure not to break anything on Unix, Win
     * or MacOS (fCmd.test, fileName.test and cmdAH.test exercise
     * most of the code).
     */
    name = Tcl_GetStringFromObj(objPtr,&len);

    /*
     * Handle tilde substitutions, if needed.
     */
    if (name[0] == '~') {
	char *expandedUser;
	Tcl_DString temp;
	int split;
	char separator='/';
	
	if (tclPlatform==TCL_PLATFORM_MAC) {
	    if (strchr(name, ':') != NULL) separator = ':';
	}
	
	split = FindSplitPos(name, &separator);
	if (split != len) {
	    /* We have multiple pieces '~user/foo/bar...' */
	    name[split] = '\0';
	}
	/* Do some tilde substitution */
	if (name[1] == '\0') {
	    /* We have just '~' */







|

|







|


















|














|







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
 * Side effects:
 *	The old representation may be freed, and new memory allocated.
 *
 *---------------------------------------------------------------------------
 */

static int
SetFsPathFromAny(interp, pathPtr)
    Tcl_Interp *interp;		/* Used for error reporting if not NULL. */
    Tcl_Obj *pathPtr;		/* The object to convert. */
{
    int len;
    FsPath *fsPathPtr;
    Tcl_Obj *transPtr;
    char *name;
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tclFsDataKey);
    
    if (pathPtr->typePtr == &tclFsPathType) {
	return TCL_OK;
    }
    
    /* 
     * First step is to translate the filename.  This is similar to
     * Tcl_TranslateFilename, but shouldn't convert everything to
     * windows backslashes on that platform.  The current
     * implementation of this piece is a slightly optimised version
     * of the various Tilde/Split/Join stuff to avoid multiple
     * split/join operations.
     * 
     * We remove any trailing directory separator.
     * 
     * However, the split/join routines are quite complex, and
     * one has to make sure not to break anything on Unix, Win
     * or MacOS (fCmd.test, fileName.test and cmdAH.test exercise
     * most of the code).
     */
    name = Tcl_GetStringFromObj(pathPtr,&len);

    /*
     * Handle tilde substitutions, if needed.
     */
    if (name[0] == '~') {
	char *expandedUser;
	Tcl_DString temp;
	int split;
	char separator='/';
	
	if (tclPlatform==TCL_PLATFORM_MAC) {
	    if (strchr(name, ':') != NULL) separator = ':';
	}
	
	split = FindSplitPos(name, separator);
	if (split != len) {
	    /* We have multiple pieces '~user/foo/bar...' */
	    name[split] = '\0';
	}
	/* Do some tilde substitution */
	if (name[1] == '\0') {
	    /* We have just '~' */
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
		 * Make use of Split/Join machinery to get it right.
		 * Assumes all paths beginning with ~ are part of the
		 * native filesystem.
		 */

		int objc;
		Tcl_Obj **objv;
		Tcl_Obj *parts = TclpNativeSplitPath(objPtr, NULL);
		Tcl_ListObjGetElements(NULL, parts, &objc, &objv);
		/* Skip '~'.  It's replaced by its expansion */
		objc--; objv++;
		while (objc--) {
		    TclpNativeJoinPath(transPtr, Tcl_GetString(*objv++));
		}
		Tcl_DecrRefCount(parts);
	    } else {

		/* Simple case. "rest" is relative path.  Just join it. */





		Tcl_Obj *rest = Tcl_NewStringObj(name+split+1,-1);

		transPtr = Tcl_FSJoinToPath(transPtr, 1, &rest);


	    }
	}
	Tcl_DStringFree(&temp);
    } else {
	transPtr = Tcl_FSJoinToPath(objPtr,0,NULL);
    }

#if defined(__CYGWIN__) && defined(__WIN32__)
    {
    extern int cygwin_conv_to_win32_path 
	_ANSI_ARGS_((CONST char *, char *));
    char winbuf[MAX_PATH+1];







|








>
|
>
>
>
>
>

>
|
>
>




|







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
		 * Make use of Split/Join machinery to get it right.
		 * Assumes all paths beginning with ~ are part of the
		 * native filesystem.
		 */

		int objc;
		Tcl_Obj **objv;
		Tcl_Obj *parts = TclpNativeSplitPath(pathPtr, NULL);
		Tcl_ListObjGetElements(NULL, parts, &objc, &objv);
		/* Skip '~'.  It's replaced by its expansion */
		objc--; objv++;
		while (objc--) {
		    TclpNativeJoinPath(transPtr, Tcl_GetString(*objv++));
		}
		Tcl_DecrRefCount(parts);
	    } else {
		/* 
		 * Simple case. "rest" is relative path.  Just join it. 
		 * The "rest" object will be freed when
		 * Tcl_FSJoinToPath returns (unless something else
		 * claims a refCount on it).
		 */
		Tcl_Obj *joined;
		Tcl_Obj *rest = Tcl_NewStringObj(name+split+1,-1);
		Tcl_IncrRefCount(transPtr);
		joined = Tcl_FSJoinToPath(transPtr, 1, &rest);
		Tcl_DecrRefCount(transPtr);
		transPtr = joined;
	    }
	}
	Tcl_DStringFree(&temp);
    } else {
	transPtr = Tcl_FSJoinToPath(pathPtr,0,NULL);
    }

#if defined(__CYGWIN__) && defined(__WIN32__)
    {
    extern int cygwin_conv_to_win32_path 
	_ANSI_ARGS_((CONST char *, char *));
    char winbuf[MAX_PATH+1];
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
     * forward slashes on Windows, and will not contain any ~user
     * sequences.
     */
    
    fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath));

    fsPathPtr->translatedPathPtr = transPtr;

    Tcl_IncrRefCount(fsPathPtr->translatedPathPtr);

    fsPathPtr->normPathPtr = NULL;
    fsPathPtr->cwdPtr = NULL;
    fsPathPtr->nativePathPtr = NULL;
    fsPathPtr->fsRecPtr = NULL;
    fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;

    /*
     * Free old representation before installing our new one.
     */
    if (objPtr->typePtr != NULL && objPtr->typePtr->freeIntRepProc != NULL) {
	(objPtr->typePtr->freeIntRepProc)(objPtr);
    }
    PATHOBJ(objPtr) = (VOID *) fsPathPtr;
    PATHFLAGS(objPtr) = 0;
    objPtr->typePtr = &tclFsPathType;

    return TCL_OK;
}

static void
FreeFsPathInternalRep(pathObjPtr)
    Tcl_Obj *pathObjPtr;	/* Path object with internal rep to free. */
{
    FsPath* fsPathPtr = (FsPath*) PATHOBJ(pathObjPtr);

    if (fsPathPtr->translatedPathPtr != NULL) {
	if (fsPathPtr->translatedPathPtr != pathObjPtr) {
	    Tcl_DecrRefCount(fsPathPtr->translatedPathPtr);
	}
    }
    if (fsPathPtr->normPathPtr != NULL) {
	if (fsPathPtr->normPathPtr != pathObjPtr) {
	    Tcl_DecrRefCount(fsPathPtr->normPathPtr);
	}
	fsPathPtr->normPathPtr = NULL;
    }
    if (fsPathPtr->cwdPtr != NULL) {
	Tcl_DecrRefCount(fsPathPtr->cwdPtr);
    }







>
|
>









|
|

|
|
|





|
|

|


|




|







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
     * forward slashes on Windows, and will not contain any ~user
     * sequences.
     */
    
    fsPathPtr = (FsPath*)ckalloc((unsigned)sizeof(FsPath));

    fsPathPtr->translatedPathPtr = transPtr;
    if (transPtr != pathPtr) {
        Tcl_IncrRefCount(fsPathPtr->translatedPathPtr);
    }
    fsPathPtr->normPathPtr = NULL;
    fsPathPtr->cwdPtr = NULL;
    fsPathPtr->nativePathPtr = NULL;
    fsPathPtr->fsRecPtr = NULL;
    fsPathPtr->filesystemEpoch = tsdPtr->filesystemEpoch;

    /*
     * Free old representation before installing our new one.
     */
    if (pathPtr->typePtr != NULL && pathPtr->typePtr->freeIntRepProc != NULL) {
	(pathPtr->typePtr->freeIntRepProc)(pathPtr);
    }
    PATHOBJ(pathPtr) = (VOID *) fsPathPtr;
    PATHFLAGS(pathPtr) = 0;
    pathPtr->typePtr = &tclFsPathType;

    return TCL_OK;
}

static void
FreeFsPathInternalRep(pathPtr)
    Tcl_Obj *pathPtr;	/* Path object with internal rep to free. */
{
    FsPath* fsPathPtr = (FsPath*) PATHOBJ(pathPtr);

    if (fsPathPtr->translatedPathPtr != NULL) {
	if (fsPathPtr->translatedPathPtr != pathPtr) {
	    Tcl_DecrRefCount(fsPathPtr->translatedPathPtr);
	}
    }
    if (fsPathPtr->normPathPtr != NULL) {
	if (fsPathPtr->normPathPtr != pathPtr) {
	    Tcl_DecrRefCount(fsPathPtr->normPathPtr);
	}
	fsPathPtr->normPathPtr = NULL;
    }
    if (fsPathPtr->cwdPtr != NULL) {
	Tcl_DecrRefCount(fsPathPtr->cwdPtr);
    }
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
	    ckfree((char *)fsPathPtr->fsRecPtr);
	}
    }

    ckfree((char*) fsPathPtr);
}


static void
DupFsPathInternalRep(srcPtr, copyPtr)
    Tcl_Obj *srcPtr;		/* Path obj with internal rep to copy. */
    Tcl_Obj *copyPtr;		/* Path obj with internal rep to set. */
{
    FsPath* srcFsPathPtr = (FsPath*) PATHOBJ(srcPtr);
    FsPath* copyFsPathPtr = (FsPath*) ckalloc((unsigned)sizeof(FsPath));







<







2294
2295
2296
2297
2298
2299
2300

2301
2302
2303
2304
2305
2306
2307
	    ckfree((char *)fsPathPtr->fsRecPtr);
	}
    }

    ckfree((char*) fsPathPtr);
}


static void
DupFsPathInternalRep(srcPtr, copyPtr)
    Tcl_Obj *srcPtr;		/* Path obj with internal rep to copy. */
    Tcl_Obj *copyPtr;		/* Path obj with internal rep to set. */
{
    FsPath* srcFsPathPtr = (FsPath*) PATHOBJ(srcPtr);
    FsPath* copyFsPathPtr = (FsPath*) ckalloc((unsigned)sizeof(FsPath));
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
 * Side effects:
 *	Memory may be allocated.
 *
 *---------------------------------------------------------------------------
 */

static void
UpdateStringOfFsPath(objPtr)
    register Tcl_Obj *objPtr;	/* path obj with string rep to update. */
{
    FsPath* fsPathPtr = (FsPath*) PATHOBJ(objPtr);
    CONST char *cwdStr;
    int cwdLen;
    Tcl_Obj *copy;
    
    if (PATHFLAGS(objPtr) == 0 || fsPathPtr->cwdPtr == NULL) {
	panic("Called UpdateStringOfFsPath with invalid object");
    }
    
    copy = Tcl_DuplicateObj(fsPathPtr->cwdPtr);
    Tcl_IncrRefCount(copy);
    
    cwdStr = Tcl_GetStringFromObj(copy, &cwdLen);
    /* 







|
|

|




|
|







2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
 * Side effects:
 *	Memory may be allocated.
 *
 *---------------------------------------------------------------------------
 */

static void
UpdateStringOfFsPath(pathPtr)
    register Tcl_Obj *pathPtr;	/* path obj with string rep to update. */
{
    FsPath* fsPathPtr = (FsPath*) PATHOBJ(pathPtr);
    CONST char *cwdStr;
    int cwdLen;
    Tcl_Obj *copy;
    
    if (PATHFLAGS(pathPtr) == 0 || fsPathPtr->cwdPtr == NULL) {
	Tcl_Panic("Called UpdateStringOfFsPath with invalid object");
    }
    
    copy = Tcl_DuplicateObj(fsPathPtr->cwdPtr);
    Tcl_IncrRefCount(copy);
    
    cwdStr = Tcl_GetStringFromObj(copy, &cwdLen);
    /* 
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
	    if (cwdStr[cwdLen-1] != ':') {
		Tcl_AppendToObj(copy, ":", 1);
		cwdLen++;
	    }
	    break;
    }
    Tcl_AppendObjToObj(copy, fsPathPtr->normPathPtr);
    objPtr->bytes = Tcl_GetStringFromObj(copy, &cwdLen);
    objPtr->length = cwdLen;
    copy->bytes = tclEmptyStringRep;
    copy->length = 0;
    Tcl_DecrRefCount(copy);
}

/*
 *---------------------------------------------------------------------------







|
|







2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
	    if (cwdStr[cwdLen-1] != ':') {
		Tcl_AppendToObj(copy, ":", 1);
		cwdLen++;
	    }
	    break;
    }
    Tcl_AppendObjToObj(copy, fsPathPtr->normPathPtr);
    pathPtr->bytes = Tcl_GetStringFromObj(copy, &cwdLen);
    pathPtr->length = cwdLen;
    copy->bytes = tclEmptyStringRep;
    copy->length = 0;
    Tcl_DecrRefCount(copy);
}

/*
 *---------------------------------------------------------------------------
Changes to generic/tclPkg.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclPkg.c --
 *
 *	This file implements package and version control for Tcl via
 *	the "package" command and a few C APIs.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclPkg.c,v 1.9 2002/02/22 22:36:09 dgp Exp $
 */

#include "tclInt.h"

/*
 * Each invocation of the "package ifneeded" command creates a structure
 * of the following type, which is used to load the package into the











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclPkg.c --
 *
 *	This file implements package and version control for Tcl via
 *	the "package" command and a few C APIs.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclPkg.c,v 1.9.4.1 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"

/*
 * Each invocation of the "package ifneeded" command creates a structure
 * of the following type, which is used to load the package into the
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
		return TCL_ERROR;
	    }
	    ComparePkgVersions(argv2, argv3, &satisfies);
	    Tcl_SetIntObj(Tcl_GetObjResult(interp), satisfies);
	    break;
	}
	default: {
	    panic("Tcl_PackageObjCmd: bad option index to pkgOptions");
	}
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------







|







790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
		return TCL_ERROR;
	    }
	    ComparePkgVersions(argv2, argv3, &satisfies);
	    Tcl_SetIntObj(Tcl_GetObjResult(interp), satisfies);
	    break;
	}
	default: {
	    Tcl_Panic("Tcl_PackageObjCmd: bad option index to pkgOptions");
	}
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
Changes to generic/tclPreserve.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 * Copyright (c) 1991-1994 The Regents of the University of California.
 * Copyright (c) 1994-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.
 *
 * RCS: @(#) $Id: tclPreserve.c,v 1.3.36.1 2003/08/07 21:36:00 dgp Exp $
 */

#include "tclInt.h"

/*
 * The following data structure is used to keep track of all the
 * Tcl_Preserve calls that are still in effect.  It grows as needed







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 * Copyright (c) 1991-1994 The Regents of the University of California.
 * Copyright (c) 1994-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.
 *
 * RCS: @(#) $Id: tclPreserve.c,v 1.3.36.2 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"

/*
 * The following data structure is used to keep track of all the
 * Tcl_Preserve calls that are still in effect.  It grows as needed
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
    }
    Tcl_MutexUnlock(&preserveMutex);

    /*
     * Reference not found.  This is a bug in the caller.
     */

    panic("Tcl_Release couldn't find reference for 0x%x", clientData);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_EventuallyFree --
 *







|







247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
    }
    Tcl_MutexUnlock(&preserveMutex);

    /*
     * Reference not found.  This is a bug in the caller.
     */

    Tcl_Panic("Tcl_Release couldn't find reference for 0x%x", clientData);
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_EventuallyFree --
 *
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302

    Tcl_MutexLock(&preserveMutex);
    for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
	if (refPtr->clientData != clientData) {
	    continue;
	}
	if (refPtr->mustFree) {
	    panic("Tcl_EventuallyFree called twice for 0x%x\n", clientData);
        }
        refPtr->mustFree = 1;
	refPtr->freeProc = freeProc;
	Tcl_MutexUnlock(&preserveMutex);
        return;
    }
    Tcl_MutexUnlock(&preserveMutex);







|







288
289
290
291
292
293
294
295
296
297
298
299
300
301
302

    Tcl_MutexLock(&preserveMutex);
    for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
	if (refPtr->clientData != clientData) {
	    continue;
	}
	if (refPtr->mustFree) {
	    Tcl_Panic("Tcl_EventuallyFree called twice for 0x%x\n", clientData);
        }
        refPtr->mustFree = 1;
	refPtr->freeProc = freeProc;
	Tcl_MutexUnlock(&preserveMutex);
        return;
    }
    Tcl_MutexUnlock(&preserveMutex);
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
				 * doubly dereferencing it will give NULL. */
{
    HandleStruct *handlePtr;

    handlePtr = (HandleStruct *) handle;
#ifdef TCL_MEM_DEBUG
    if (handlePtr->refCount == 0x61616161) {
	panic("using previously disposed TclHandle %x", handlePtr);
    }
    if (handlePtr->ptr2 != handlePtr->ptr) {
	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((char *) handlePtr);
    }







|


|







383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
				 * doubly 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((char *) handlePtr);
    }
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
				 * memory referenced by this handle. */
{
    HandleStruct *handlePtr;

    handlePtr = (HandleStruct *) handle;
#ifdef TCL_MEM_DEBUG
    if (handlePtr->refCount == 0x61616161) {
	panic("using previously disposed TclHandle %x", handlePtr);
    }
    if ((handlePtr->ptr != NULL)
	    && (handlePtr->ptr != handlePtr->ptr2)) {
	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;
}







|



|







426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
				 * memory 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;
}
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
				 * memory referenced by this handle. */
{
    HandleStruct *handlePtr;

    handlePtr = (HandleStruct *) handle;
#ifdef TCL_MEM_DEBUG
    if (handlePtr->refCount == 0x61616161) {
	panic("using previously disposed TclHandle %x", handlePtr);
    }
    if ((handlePtr->ptr != NULL)
	    && (handlePtr->ptr != handlePtr->ptr2)) {
	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((char *) handlePtr);
    }
}
    







|



|









468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
				 * memory 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((char *) handlePtr);
    }
}
    
Changes to generic/tclProc.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclProc.c --
 *
 *	This file contains routines that implement Tcl procedures,
 *	including the "proc" and "uplevel" commands.
 *
 * Copyright (c) 1987-1993 The Regents of the University of California.
 * Copyright (c) 1994-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.
 *
 * RCS: @(#) $Id: tclProc.c,v 1.46.2.2 2003/10/16 02:28:02 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"

/*
 * Prototypes for static functions in this file












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclProc.c --
 *
 *	This file contains routines that implement Tcl procedures,
 *	including the "proc" and "uplevel" commands.
 *
 * Copyright (c) 1987-1993 The Regents of the University of California.
 * Copyright (c) 1994-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.
 *
 * RCS: @(#) $Id: tclProc.c,v 1.46.2.3 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclCompile.h"

/*
 * Prototypes for static functions in this file
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009

    numArgs = procPtr->numArgs;
    varPtr = framePtr->compiledLocals;
    localPtr = procPtr->firstLocalPtr;
    argCt = objc;
    for (i = 1, argCt -= 1;  i <= numArgs;  i++, argCt--) {
	if (!TclIsVarArgument(localPtr)) {
	    panic("TclObjInterpProc: local variable %s is not argument but should be",
		  localPtr->name);
	    return TCL_ERROR;
	}
	if (TclIsVarTemporary(localPtr)) {
	    panic("TclObjInterpProc: local variable %d is temporary but should be an argument", i);
	    return TCL_ERROR;
	}

	/*
	 * Handle the special case of the last formal being "args".  When
	 * it occurs, assign it a list consisting of all the remaining
	 * actual arguments.







|




|







990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009

    numArgs = procPtr->numArgs;
    varPtr = framePtr->compiledLocals;
    localPtr = procPtr->firstLocalPtr;
    argCt = objc;
    for (i = 1, argCt -= 1;  i <= numArgs;  i++, argCt--) {
	if (!TclIsVarArgument(localPtr)) {
	    Tcl_Panic("TclObjInterpProc: local variable %s is not argument but should be",
		  localPtr->name);
	    return TCL_ERROR;
	}
	if (TclIsVarTemporary(localPtr)) {
	    Tcl_Panic("TclObjInterpProc: local variable %d is temporary but should be an argument", i);
	    return TCL_ERROR;
	}

	/*
	 * Handle the special case of the last formal being "args".  When
	 * it occurs, assign it a list consisting of all the remaining
	 * actual arguments.
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
                (*tclByteCodeType.freeIntRepProc)(bodyPtr);
                bodyPtr->typePtr = (Tcl_ObjType *) NULL;
            }
 	}
    }
    if (bodyPtr->typePtr != &tclByteCodeType) {
#ifdef TCL_COMPILE_DEBUG
 	int numChars;
 	char *ellipsis;
 	
 	if (tclTraceCompile >= 1) {
 	    /*
 	     * Display a line summarizing the top level command we
 	     * are about to compile.
 	     */
	    Tcl_Obj *message = Tcl_NewStringObj("Compiling ", -1);
	    Tcl_IncrRefCount(message);







<
<
<







1169
1170
1171
1172
1173
1174
1175



1176
1177
1178
1179
1180
1181
1182
                (*tclByteCodeType.freeIntRepProc)(bodyPtr);
                bodyPtr->typePtr = (Tcl_ObjType *) NULL;
            }
 	}
    }
    if (bodyPtr->typePtr != &tclByteCodeType) {
#ifdef TCL_COMPILE_DEBUG



 	if (tclTraceCompile >= 1) {
 	    /*
 	     * Display a line summarizing the top level command we
 	     * are about to compile.
 	     */
	    Tcl_Obj *message = Tcl_NewStringObj("Compiling ", -1);
	    Tcl_IncrRefCount(message);
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

/*
 *----------------------------------------------------------------------
 *
 * ProcBodySetFromAny --
 *
 *  Tcl_ObjType's SetFromAny function for the proc body object.
 *  Calls panic.
 *
 * Results:
 *  Theoretically returns a TCL result code.
 *
 * Side effects:
 *  Calls panic, since we can't set the value of the object from a string
 *  representation (or any other internal ones).
 *
 *----------------------------------------------------------------------
 */

static int
ProcBodySetFromAny(interp, objPtr)
    Tcl_Interp *interp;			/* current interpreter */
    Tcl_Obj *objPtr;			/* object pointer */
{
    panic("called ProcBodySetFromAny");

    /*
     * this to keep compilers happy.
     */
    
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * ProcBodyUpdateString --
 *
 *  Tcl_ObjType's UpdateString function for the proc body object.
 *  Calls panic.
 *
 * Results:
 *  None.
 *
 * Side effects:
 *  Calls panic, since we this type has no string representation.
 *
 *----------------------------------------------------------------------
 */

static void
ProcBodyUpdateString(objPtr)
    Tcl_Obj *objPtr;		/* the object to update */
{
    panic("called ProcBodyUpdateString");
}


/*
 *----------------------------------------------------------------------
 *
 * TclCompileNoOp --







|





|
|









|














|





|








|







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

/*
 *----------------------------------------------------------------------
 *
 * ProcBodySetFromAny --
 *
 *  Tcl_ObjType's SetFromAny function for the proc body object.
 *  Calls Tcl_Panic.
 *
 * Results:
 *  Theoretically returns a TCL result code.
 *
 * Side effects:
 *  Calls Tcl_Panic, since we can't set the value of the object from a
 *  string representation (or any other internal ones).
 *
 *----------------------------------------------------------------------
 */

static int
ProcBodySetFromAny(interp, objPtr)
    Tcl_Interp *interp;			/* current interpreter */
    Tcl_Obj *objPtr;			/* object pointer */
{
    Tcl_Panic("called ProcBodySetFromAny");

    /*
     * this to keep compilers happy.
     */
    
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * ProcBodyUpdateString --
 *
 *  Tcl_ObjType's UpdateString function for the proc body object.
 *  Calls Tcl_Panic.
 *
 * Results:
 *  None.
 *
 * Side effects:
 *  Calls Tcl_Panic, since we this type has no string representation.
 *
 *----------------------------------------------------------------------
 */

static void
ProcBodyUpdateString(objPtr)
    Tcl_Obj *objPtr;		/* the object to update */
{
    Tcl_Panic("called ProcBodyUpdateString");
}


/*
 *----------------------------------------------------------------------
 *
 * TclCompileNoOp --
Changes to generic/tclStringObj.c.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 * Copyright (c) 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.
 *
 * RCS: @(#) $Id: tclStringObj.c,v 1.32.4.1 2003/10/16 02:28:02 dgp Exp $ */

#include "tclInt.h"

/*
 * Prototypes for procedures defined later in this file:
 */








|







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 * Copyright (c) 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.
 *
 * RCS: @(#) $Id: tclStringObj.c,v 1.32.4.2 2004/02/07 05:48:01 dgp Exp $ */

#include "tclInt.h"

/*
 * Prototypes for procedures defined later in this file:
 */

703
704
705
706
707
708
709
710
711
712
713
714
715
716
717

    /*
     * Free any old string rep, then set the string rep to a copy of
     * the length bytes starting at "bytes".
     */

    if (Tcl_IsShared(objPtr)) {
	panic("Tcl_SetStringObj called with shared object");
    }

    /*
     * Set the type to NULL and free any internal rep for the old type.
     */

    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {







|







703
704
705
706
707
708
709
710
711
712
713
714
715
716
717

    /*
     * Free any old string rep, then set the string rep to a copy of
     * the length bytes starting at "bytes".
     */

    if (Tcl_IsShared(objPtr)) {
	Tcl_Panic("Tcl_SetStringObj called with shared object");
    }

    /*
     * Set the type to NULL and free any internal rep for the old type.
     */

    if ((oldTypePtr != NULL) && (oldTypePtr->freeIntRepProc != NULL)) {
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
    register int length;	/* Number of bytes desired for string
				 * representation of object, not including
				 * terminating null byte. */
{
    String *stringPtr;

    if (Tcl_IsShared(objPtr)) {
	panic("Tcl_SetObjLength called with shared object");
    }
    SetStringFromAny(NULL, objPtr);
    
    stringPtr = GET_STRING(objPtr);
    
    /* Check that we're not extending a pure unicode string */
    







|







757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
    register int length;	/* Number of bytes desired for string
				 * representation of object, not including
				 * terminating null byte. */
{
    String *stringPtr;

    if (Tcl_IsShared(objPtr)) {
	Tcl_Panic("Tcl_SetObjLength called with shared object");
    }
    SetStringFromAny(NULL, objPtr);
    
    stringPtr = GET_STRING(objPtr);
    
    /* Check that we're not extending a pure unicode string */
    
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
    register int length;	/* Number of bytes desired for string
				 * representation of object, not including
				 * terminating null byte. */
{
    String *stringPtr;

    if (Tcl_IsShared(objPtr)) {
	panic("Tcl_AttemptSetObjLength called with shared object");
    }
    SetStringFromAny(NULL, objPtr);
        
    stringPtr = GET_STRING(objPtr);

    /* Check that we're not extending a pure unicode string */








|







852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
    register int length;	/* Number of bytes desired for string
				 * representation of object, not including
				 * terminating null byte. */
{
    String *stringPtr;

    if (Tcl_IsShared(objPtr)) {
	Tcl_Panic("Tcl_AttemptSetObjLength called with shared object");
    }
    SetStringFromAny(NULL, objPtr);
        
    stringPtr = GET_STRING(objPtr);

    /* Check that we're not extending a pure unicode string */

1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
				 * the object to indicate not all available
				 * bytes at "bytes" were appended. */
{
    String *stringPtr;
    int toCopy = 0;

    if (Tcl_IsShared(objPtr)) {
	panic("TclAppendLimitedToObj called with shared object");
    }

    SetStringFromAny(NULL, objPtr);

    if (length < 0) {
	length = (bytes ? strlen(bytes) : 0);
    }







|







1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
				 * the object to indicate not all available
				 * bytes at "bytes" were appended. */
{
    String *stringPtr;
    int toCopy = 0;

    if (Tcl_IsShared(objPtr)) {
	Tcl_Panic("TclAppendLimitedToObj called with shared object");
    }

    SetStringFromAny(NULL, objPtr);

    if (length < 0) {
	length = (bytes ? strlen(bytes) : 0);
    }
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
    CONST Tcl_UniChar *unicode;	/* The unicode string to append to the
			         * object. */
    int length;			/* Number of chars in "unicode". */
{
    String *stringPtr;

    if (Tcl_IsShared(objPtr)) {
	panic("Tcl_AppendUnicodeToObj called with shared object");
    }

    if (length == 0) {
	return;
    }

    SetStringFromAny(NULL, objPtr);







|







1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
    CONST Tcl_UniChar *unicode;	/* The unicode string to append to the
			         * object. */
    int length;			/* Number of chars in "unicode". */
{
    String *stringPtr;

    if (Tcl_IsShared(objPtr)) {
	Tcl_Panic("Tcl_AppendUnicodeToObj called with shared object");
    }

    if (length == 0) {
	return;
    }

    SetStringFromAny(NULL, objPtr);
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
    register char *string, *dst;
    char *static_list[STATIC_LIST_SIZE];
    char **args = static_list;
    int nargs_space = STATIC_LIST_SIZE;
    int nargs, i;

    if (Tcl_IsShared(objPtr)) {
	panic("Tcl_AppendStringsToObj called with shared object");
    }

    SetStringFromAny(NULL, objPtr);

    /*
     * Figure out how much space is needed for all the strings, and
     * expand the string representation if it isn't big enough. If no







|







1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
    register char *string, *dst;
    char *static_list[STATIC_LIST_SIZE];
    char **args = static_list;
    int nargs_space = STATIC_LIST_SIZE;
    int nargs, i;

    if (Tcl_IsShared(objPtr)) {
	Tcl_Panic("Tcl_AppendStringsToObj called with shared object");
    }

    SetStringFromAny(NULL, objPtr);

    /*
     * Figure out how much space is needed for all the strings, and
     * expand the string representation if it isn't big enough. If no
Changes to generic/tclStubInit.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 
 * tclStubInit.c --
 *
 *	This file contains the initializers for the Tcl stub vectors.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclStubInit.c,v 1.84.2.7 2003/10/16 02:29:16 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * Remove macros that will interfere with the definitions below.










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 
 * tclStubInit.c --
 *
 *	This file contains the initializers for the Tcl stub vectors.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclStubInit.c,v 1.84.2.8 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * Remove macros that will interfere with the definitions below.
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#endif /* __WIN32__ */
#ifdef MAC_TCL
    NULL, /* 9 */
#endif /* MAC_TCL */
    TclCreateProc, /* 10 */
    TclDeleteCompiledLocalVars, /* 11 */
    TclDeleteVars, /* 12 */
    TclDoGlob, /* 13 */
    TclDumpMemoryInfo, /* 14 */
    NULL, /* 15 */
    TclExprFloatError, /* 16 */
    NULL, /* 17 */
    NULL, /* 18 */
    NULL, /* 19 */
    NULL, /* 20 */







|







95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#endif /* __WIN32__ */
#ifdef MAC_TCL
    NULL, /* 9 */
#endif /* MAC_TCL */
    TclCreateProc, /* 10 */
    TclDeleteCompiledLocalVars, /* 11 */
    TclDeleteVars, /* 12 */
    NULL, /* 13 */
    TclDumpMemoryInfo, /* 14 */
    NULL, /* 15 */
    TclExprFloatError, /* 16 */
    NULL, /* 17 */
    NULL, /* 18 */
    NULL, /* 19 */
    NULL, /* 20 */
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
    Tcl_PopCallFrame, /* 128 */
    Tcl_PushCallFrame, /* 129 */
    Tcl_RemoveInterpResolvers, /* 130 */
    Tcl_SetNamespaceResolvers, /* 131 */
    TclpHasSockets, /* 132 */
    TclpGetDate, /* 133 */
    TclpStrftime, /* 134 */
    TclpCheckStackSpace, /* 135 */
    NULL, /* 136 */
    NULL, /* 137 */
    TclGetEnv, /* 138 */
    NULL, /* 139 */
    TclLooksLikeInt, /* 140 */
    TclpGetCwd, /* 141 */
    TclSetByteCodeFromAny, /* 142 */







|







225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
    Tcl_PopCallFrame, /* 128 */
    Tcl_PushCallFrame, /* 129 */
    Tcl_RemoveInterpResolvers, /* 130 */
    Tcl_SetNamespaceResolvers, /* 131 */
    TclpHasSockets, /* 132 */
    TclpGetDate, /* 133 */
    TclpStrftime, /* 134 */
    NULL, /* 135 */
    NULL, /* 136 */
    NULL, /* 137 */
    TclGetEnv, /* 138 */
    NULL, /* 139 */
    TclLooksLikeInt, /* 140 */
    TclpGetCwd, /* 141 */
    TclSetByteCodeFromAny, /* 142 */
270
271
272
273
274
275
276


277
278
279
280
281
282
283
    TclUniCharMatch, /* 173 */
    TclIncrWideVar2, /* 174 */
    TclCallVarTraces, /* 175 */
    TclCleanupVar, /* 176 */
    TclVarErrMsg, /* 177 */
    Tcl_SetStartupScript, /* 178 */
    Tcl_GetStartupScript, /* 179 */


};

TclIntPlatStubs tclIntPlatStubs = {
    TCL_STUB_MAGIC,
    NULL,
#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */
    TclGetAndDetachPids, /* 0 */







>
>







270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
    TclUniCharMatch, /* 173 */
    TclIncrWideVar2, /* 174 */
    TclCallVarTraces, /* 175 */
    TclCleanupVar, /* 176 */
    TclVarErrMsg, /* 177 */
    Tcl_SetStartupScript, /* 178 */
    Tcl_GetStartupScript, /* 179 */
    TclNewListObjDirect, /* 180 */
    TclDbNewListObjDirect, /* 181 */
};

TclIntPlatStubs tclIntPlatStubs = {
    TCL_STUB_MAGIC,
    NULL,
#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */
    TclGetAndDetachPids, /* 0 */
Changes to generic/tclTest.c.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 Ajuba Solutions.
 * Copyright (c) 2003 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclTest.c,v 1.67.2.1 2003/10/16 02:28:02 dgp Exp $
 */

#define TCL_TEST
#include "tclInt.h"
#include "tclPort.h"

/*







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 Ajuba Solutions.
 * Copyright (c) 2003 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclTest.c,v 1.67.2.2 2004/02/07 05:48:01 dgp Exp $
 */

#define TCL_TEST
#include "tclInt.h"
#include "tclPort.h"

/*
125
126
127
128
129
130
131



132
133
134
135
136
137
138
/*
 * Forward declarations for procedures defined later in this file:
 */

int			Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp));
static int		AsyncHandlerProc _ANSI_ARGS_((ClientData clientData,
			    Tcl_Interp *interp, int code));



static void		CleanupTestSetassocdataTests _ANSI_ARGS_((
			    ClientData clientData, Tcl_Interp *interp));
static void		CmdDelProc1 _ANSI_ARGS_((ClientData clientData));
static void		CmdDelProc2 _ANSI_ARGS_((ClientData clientData));
static int		CmdProc1 _ANSI_ARGS_((ClientData clientData,
			    Tcl_Interp *interp, int argc, CONST char **argv));
static int		CmdProc2 _ANSI_ARGS_((ClientData clientData,







>
>
>







125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 * Forward declarations for procedures defined later in this file:
 */

int			Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp));
static int		AsyncHandlerProc _ANSI_ARGS_((ClientData clientData,
			    Tcl_Interp *interp, int code));
#ifdef TCL_THREADS
static Tcl_ThreadCreateType AsyncThreadProc _ANSI_ARGS_((ClientData));
#endif
static void		CleanupTestSetassocdataTests _ANSI_ARGS_((
			    ClientData clientData, Tcl_Interp *interp));
static void		CmdDelProc1 _ANSI_ARGS_((ClientData clientData));
static void		CmdDelProc2 _ANSI_ARGS_((ClientData clientData));
static int		CmdProc1 _ANSI_ARGS_((ClientData clientData,
			    Tcl_Interp *interp, int argc, CONST char **argv));
static int		CmdProc2 _ANSI_ARGS_((ClientData clientData,
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
			    ClientData dummy, Tcl_Interp *interp, int objc, 
			    Tcl_Obj *CONST objv[]));

static void             TestReport _ANSI_ARGS_ ((CONST char* cmd, Tcl_Obj* arg1, 
			    Tcl_Obj* arg2));

static Tcl_Obj*         TestReportGetNativePath _ANSI_ARGS_ ((
			    Tcl_Obj* pathObjPtr));

static int		TestReportStat _ANSI_ARGS_ ((Tcl_Obj *path,
			    Tcl_StatBuf *buf));
static int		TestReportAccess _ANSI_ARGS_ ((Tcl_Obj *path,
			    int mode));
static Tcl_Channel	TestReportOpenFileChannel _ANSI_ARGS_ ((
			    Tcl_Interp *interp, Tcl_Obj *fileName,







|







361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
			    ClientData dummy, Tcl_Interp *interp, int objc, 
			    Tcl_Obj *CONST objv[]));

static void             TestReport _ANSI_ARGS_ ((CONST char* cmd, Tcl_Obj* arg1, 
			    Tcl_Obj* arg2));

static Tcl_Obj*         TestReportGetNativePath _ANSI_ARGS_ ((
			    Tcl_Obj* pathPtr));

static int		TestReportStat _ANSI_ARGS_ ((Tcl_Obj *path,
			    Tcl_StatBuf *buf));
static int		TestReportAccess _ANSI_ARGS_ ((Tcl_Obj *path,
			    int mode));
static Tcl_Channel	TestReportOpenFileChannel _ANSI_ARGS_ ((
			    Tcl_Interp *interp, Tcl_Obj *fileName,
415
416
417
418
419
420
421
422




423
424



425
426
427
428
429
430
431
			    int mode));
static Tcl_Channel	SimpleOpenFileChannel _ANSI_ARGS_ ((
			    Tcl_Interp *interp, Tcl_Obj *fileName,
			    int mode, int permissions));
static Tcl_Obj*         SimpleListVolumes _ANSI_ARGS_ ((void));
static int              SimplePathInFilesystem _ANSI_ARGS_ ((
			    Tcl_Obj *pathPtr, ClientData *clientDataPtr));
static Tcl_Obj*         SimpleCopy _ANSI_ARGS_ ((Tcl_Obj *pathPtr));




static int              TestNumUtfCharsCmd _ANSI_ARGS_((ClientData clientData,
                            Tcl_Interp *interp, int objc,



			    Tcl_Obj *CONST objv[]));

static Tcl_Filesystem testReportingFilesystem = {
    "reporting",
    sizeof(Tcl_Filesystem),
    TCL_FILESYSTEM_VERSION_1,
    &TestReportInFilesystem, /* path in */







|
>
>
>
>


>
>
>







418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
			    int mode));
static Tcl_Channel	SimpleOpenFileChannel _ANSI_ARGS_ ((
			    Tcl_Interp *interp, Tcl_Obj *fileName,
			    int mode, int permissions));
static Tcl_Obj*         SimpleListVolumes _ANSI_ARGS_ ((void));
static int              SimplePathInFilesystem _ANSI_ARGS_ ((
			    Tcl_Obj *pathPtr, ClientData *clientDataPtr));
static Tcl_Obj*         SimpleRedirect _ANSI_ARGS_ ((Tcl_Obj *pathPtr));
static int		SimpleMatchInDirectory _ANSI_ARGS_ ((
			    Tcl_Interp *interp, Tcl_Obj *resultPtr,
			    Tcl_Obj *dirPtr, CONST char *pattern,
			    Tcl_GlobTypeData *types));
static int              TestNumUtfCharsCmd _ANSI_ARGS_((ClientData clientData,
                            Tcl_Interp *interp, int objc,
			    Tcl_Obj *CONST objv[]));
static int              TestHashSystemHashCmd _ANSI_ARGS_((ClientData clientData,
                            Tcl_Interp *interp, int objc,
			    Tcl_Obj *CONST objv[]));

static Tcl_Filesystem testReportingFilesystem = {
    "reporting",
    sizeof(Tcl_Filesystem),
    TCL_FILESYSTEM_VERSION_1,
    &TestReportInFilesystem, /* path in */
475
476
477
478
479
480
481
482

483
484
485
486
487
488
489
     * one representation */
    NULL,
    NULL,
    NULL,
    &SimpleStat,
    &SimpleAccess,
    &SimpleOpenFileChannel,
    NULL,

    NULL,
    /* We choose not to support symbolic links inside our vfs's */
    NULL,
    &SimpleListVolumes,
    NULL,
    NULL,
    NULL,







<
>







485
486
487
488
489
490
491

492
493
494
495
496
497
498
499
     * one representation */
    NULL,
    NULL,
    NULL,
    &SimpleStat,
    &SimpleAccess,
    &SimpleOpenFileChannel,

    &SimpleMatchInDirectory,
    NULL,
    /* We choose not to support symbolic links inside our vfs's */
    NULL,
    &SimpleListVolumes,
    NULL,
    NULL,
    NULL,
616
617
618
619
620
621
622



623
624
625
626
627
628
629
            (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
    Tcl_CreateCommand(interp, "testfevent", TestfeventCmd, (ClientData) 0,
            (Tcl_CmdDeleteProc *) NULL);
    Tcl_CreateObjCommand(interp, "testfilelink", TestfilelinkCmd, 
            (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
    Tcl_CreateObjCommand(interp, "testfile", TestfileCmd,
            (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);



    Tcl_CreateCommand(interp, "testgetassocdata", TestgetassocdataCmd,
            (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
    Tcl_CreateCommand(interp, "testgetplatform", TestgetplatformCmd,
	    (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
    Tcl_CreateObjCommand(interp, "testgetvarfullname",
	    TestgetvarfullnameCmd, (ClientData) 0,
	    (Tcl_CmdDeleteProc *) NULL);







>
>
>







626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
            (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
    Tcl_CreateCommand(interp, "testfevent", TestfeventCmd, (ClientData) 0,
            (Tcl_CmdDeleteProc *) NULL);
    Tcl_CreateObjCommand(interp, "testfilelink", TestfilelinkCmd, 
            (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
    Tcl_CreateObjCommand(interp, "testfile", TestfileCmd,
            (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
    Tcl_CreateObjCommand(interp, "testhashsystemhash",
	    TestHashSystemHashCmd, (ClientData) 0, 
	    (Tcl_CmdDeleteProc *) NULL);
    Tcl_CreateCommand(interp, "testgetassocdata", TestgetassocdataCmd,
            (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
    Tcl_CreateCommand(interp, "testgetplatform", TestgetplatformCmd,
	    (ClientData) 0, (Tcl_CmdDeleteProc *) NULL);
    Tcl_CreateObjCommand(interp, "testgetvarfullname",
	    TestgetvarfullnameCmd, (ClientData) 0,
	    (Tcl_CmdDeleteProc *) NULL);
830
831
832
833
834
835
836



























837
838
839
840
841

842
843
844
845
846
847
848
	    if (asyncPtr->id == id) {
		Tcl_AsyncMark(asyncPtr->handler);
		break;
	    }
	}
	Tcl_SetResult(interp, (char *)argv[3], TCL_VOLATILE);
	return code;



























    } else {
	Tcl_AppendResult(interp, "bad option \"", argv[1],
		"\": must be create, delete, int, or mark",
		(char *) NULL);
	return TCL_ERROR;

    }
    return TCL_OK;
}

static int
AsyncHandlerProc(clientData, interp, code)
    ClientData clientData;	/* Pointer to TestAsyncHandler structure. */







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





>







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
	    if (asyncPtr->id == id) {
		Tcl_AsyncMark(asyncPtr->handler);
		break;
	    }
	}
	Tcl_SetResult(interp, (char *)argv[3], TCL_VOLATILE);
	return code;
#ifdef TCL_THREADS
    } else if (strcmp(argv[1], "marklater") == 0) {
	if (argc != 3) {
	    goto wrongNumArgs;
	}
	if (Tcl_GetInt(interp, argv[2], &id) != TCL_OK) {
	    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;
	    }
	}
    } else {
	Tcl_AppendResult(interp, "bad option \"", argv[1],
		"\": must be create, delete, int, mark, or marklater",
		(char *) NULL);
	return TCL_ERROR;
#else /* !TCL_THREADS */
    } else {
	Tcl_AppendResult(interp, "bad option \"", argv[1],
		"\": must be create, delete, int, or mark",
		(char *) NULL);
	return TCL_ERROR;
#endif
    }
    return TCL_OK;
}

static int
AsyncHandlerProc(clientData, interp, code)
    ClientData clientData;	/* Pointer to TestAsyncHandler structure. */
869
870
871
872
873
874
875






























876
877
878
879
880
881
882
	 * checking is needed here.
	 */
    }
    ckfree((char *)cmd);
    return code;
}































/*
 *----------------------------------------------------------------------
 *
 * TestcmdinfoCmd --
 *
 *	This procedure implements the "testcmdinfo" command.  It is used
 *	to test Tcl_GetCommandInfo, Tcl_SetCommandInfo, and command creation







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







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
	 * checking is needed here.
	 */
    }
    ckfree((char *)cmd);
    return code;
}

/*
 *----------------------------------------------------------------------
 *
 * AsyncThreadProc --
 *
 *	Delivers an asynchronous event to a handler in another thread.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Invokes Tcl_AsyncMark on the handler
 *
 *----------------------------------------------------------------------
 */

#ifdef TCL_THREADS
static Tcl_ThreadCreateType
AsyncThreadProc(clientData)
    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

/*
 *----------------------------------------------------------------------
 *
 * TestcmdinfoCmd --
 *
 *	This procedure implements the "testcmdinfo" command.  It is used
 *	to test Tcl_GetCommandInfo, Tcl_SetCommandInfo, and command creation
3041
3042
3043
3044
3045
3046
3047



3048
3049
3050
3051
3052
3053
3054
    Tcl_ListObjAppendElement((Tcl_Interp *) NULL, objPtr,
	    Tcl_NewStringObj(parsePtr->commandStart, parsePtr->commandSize));
    Tcl_ListObjAppendElement((Tcl_Interp *) NULL, objPtr,
	    Tcl_NewIntObj(parsePtr->numWords));
    for (i = 0; i < parsePtr->numTokens; i++) {
	tokenPtr = &parsePtr->tokenPtr[i];
	switch (tokenPtr->type) {



	    case TCL_TOKEN_WORD:
		typeString = "word";
		break;
	    case TCL_TOKEN_SIMPLE_WORD:
		typeString = "simple";
		break;
	    case TCL_TOKEN_TEXT:







>
>
>







3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
    Tcl_ListObjAppendElement((Tcl_Interp *) NULL, objPtr,
	    Tcl_NewStringObj(parsePtr->commandStart, parsePtr->commandSize));
    Tcl_ListObjAppendElement((Tcl_Interp *) NULL, objPtr,
	    Tcl_NewIntObj(parsePtr->numWords));
    for (i = 0; i < parsePtr->numTokens; i++) {
	tokenPtr = &parsePtr->tokenPtr[i];
	switch (tokenPtr->type) {
	    case TCL_TOKEN_EXPAND_WORD:
		typeString = "expand";
		break;
	    case TCL_TOKEN_WORD:
		typeString = "word";
		break;
	    case TCL_TOKEN_SIMPLE_WORD:
		typeString = "simple";
		break;
	    case TCL_TOKEN_TEXT:
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
    
    /*
     *  Put the arguments into a var args structure
     *  Append all of the arguments together separated by spaces
     */

    argString = Tcl_Merge(argc-1, argv+1);
    panic(argString);
    ckfree((char *)argString);
 
    return TCL_OK;
}

/*
 *---------------------------------------------------------------------------







|







4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
    
    /*
     *  Put the arguments into a var args structure
     *  Append all of the arguments together separated by spaces
     */

    argString = Tcl_Merge(argc-1, argv+1);
    Tcl_Panic(argString);
    ckfree((char *)argString);
 
    return TCL_OK;
}

/*
 *---------------------------------------------------------------------------
5693
5694
5695
5696
5697
5698
5699
5700
5701
5702
5703
5704
5705
5706
5707
            for (prevEsPtr = statePtr->scriptRecordPtr;
		 (prevEsPtr != (EventScriptRecord *) NULL) &&
		     (prevEsPtr->nextPtr != esPtr);
		 prevEsPtr = prevEsPtr->nextPtr) {
                /* Empty loop body. */
            }
            if (prevEsPtr == (EventScriptRecord *) NULL) {
                panic("TestChannelEventCmd: damaged event script list");
            }
            prevEsPtr->nextPtr = esPtr->nextPtr;
        }
        Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr,
                TclChannelEventScriptInvoker, (ClientData) esPtr);
	Tcl_DecrRefCount(esPtr->scriptPtr);
        ckfree((char *) esPtr);







|







5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
            for (prevEsPtr = statePtr->scriptRecordPtr;
		 (prevEsPtr != (EventScriptRecord *) NULL) &&
		     (prevEsPtr->nextPtr != esPtr);
		 prevEsPtr = prevEsPtr->nextPtr) {
                /* Empty loop body. */
            }
            if (prevEsPtr == (EventScriptRecord *) NULL) {
                Tcl_Panic("TestChannelEventCmd: damaged event script list");
            }
            prevEsPtr->nextPtr = esPtr->nextPtr;
        }
        Tcl_DeleteChannelHandler((Tcl_Channel) chanPtr,
                TclChannelEventScriptInvoker, (ClientData) esPtr);
	Tcl_DecrRefCount(esPtr->scriptPtr);
        ckfree((char *) esPtr);
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
}

/* 
 * Simple helper function to extract the native vfs representation of a
 * path object, or NULL if no such representation exists.
 */
static Tcl_Obj* 
TestReportGetNativePath(Tcl_Obj* pathObjPtr) {
    return (Tcl_Obj*) Tcl_FSGetInternalRep(pathObjPtr, &testReportingFilesystem);
}

static void 
TestReportFreeInternalRep(ClientData clientData) {
    Tcl_Obj *nativeRep = (Tcl_Obj*)clientData;
    if (nativeRep != NULL) {
	/* Free the path */







|
|







6054
6055
6056
6057
6058
6059
6060
6061
6062
6063
6064
6065
6066
6067
6068
6069
}

/* 
 * Simple helper function to extract the native vfs representation of a
 * path object, or NULL if no such representation exists.
 */
static Tcl_Obj* 
TestReportGetNativePath(Tcl_Obj* pathPtr) {
    return (Tcl_Obj*) Tcl_FSGetInternalRep(pathPtr, &testReportingFilesystem);
}

static void 
TestReportFreeInternalRep(ClientData clientData) {
    Tcl_Obj *nativeRep = (Tcl_Obj*)clientData;
    if (nativeRep != NULL) {
	/* Free the path */
6246
6247
6248
6249
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262
6263
6264
6265

6266
6267
6268
6269
6270
6271
6272
6273
6274
6275
6276
6277
6278
6279
6280
6281
6282
6283
6284
6285
6286
6287
    if (strncmp(str,"simplefs:/",10)) {
	return -1;
    }
    return TCL_OK;
}

/* 
 * Since TclCopyChannel insists on an interpreter, we use this
 * to simplify our test scripts.  Would be better if it could
 * copy without an interp
 */
static Tcl_Interp *simpleInterpPtr = NULL;
/* We use this to ensure we clean up after ourselves */
static Tcl_Obj *tempFile = NULL;

/* 
 * This is a very 'hacky' filesystem which is used just to 
 * test two important features of the vfs code: (1) that
 * you can load a shared library from a vfs, (2) that when
 * copying files from one fs to another, the 'mtime' is

 * preserved.
 * 
 * It treats any file in 'simplefs:/' as a file, and
 * artificially creates a real file on the fly which it uses
 * to extract information from.  The real file it uses is
 * whatever follows the trailing '/' (e.g. 'foo' in 'simplefs:/foo'),
 * and that file is assumed to exist in the native pwd, and is
 * copied over to the native temporary directory where it is
 * accessed.
 * 
 * Please do not consider this filesystem a model of how
 * things are to be done.  It is quite the opposite!  But, it
 * does allow us to test two important features.
 * 
 * Finally: this fs can only be used from one interpreter.
 */
static int
TestSimpleFilesystemObjCmd(dummy, interp, objc, objv)
    ClientData dummy;
    Tcl_Interp *interp;
    int		objc;
    Tcl_Obj	*CONST objv[];







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

|
<
|

|
<
|



|
<
<







6320
6321
6322
6323
6324
6325
6326









6327
6328
6329
6330
6331
6332
6333
6334

6335
6336
6337

6338
6339
6340
6341
6342


6343
6344
6345
6346
6347
6348
6349
    if (strncmp(str,"simplefs:/",10)) {
	return -1;
    }
    return TCL_OK;
}

/* 









 * This is a slightly 'hacky' filesystem which is used just to test a
 * few important features of the vfs code: (1) that you can load a
 * shared library from a vfs, (2) that when copying files from one fs to
 * another, the 'mtime' is preserved.  (3) that recursive
 * cross-filesystem directory copies have the correct behaviour
 * with/without -force.
 * 
 * It treats any file in 'simplefs:/' as a file, which it

 * routes to the current directory.  The real file it uses is
 * whatever follows the trailing '/' (e.g. 'foo' in 'simplefs:/foo'),
 * and that file exists or not according to what is in the native

 * pwd.
 * 
 * Please do not consider this filesystem a model of how
 * things are to be done.  It is quite the opposite!  But, it
 * does allow us to test some important features.


 */
static int
TestSimpleFilesystemObjCmd(dummy, interp, objc, objv)
    ClientData dummy;
    Tcl_Interp *interp;
    int		objc;
    Tcl_Obj	*CONST objv[];
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
6307
6308
6309
6310
6311
6312
6313
6314
6315
6316
6317
6318
6319
6320
6321
6322
6323
6324
6325
6326
6327
6328
6329








6330
6331
6332

6333




















6334
6335
6336
6337

6338
6339










6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
    }
    if (Tcl_GetBooleanFromObj(interp, objv[1], &boolVal) != TCL_OK) {
	return TCL_ERROR;
    }
    if (boolVal) {
	res = Tcl_FSRegister((ClientData)interp, &simpleFilesystem);
	msg = (res == TCL_OK) ? "registered" : "failed";
	simpleInterpPtr = interp;
    } else {
	if (tempFile != NULL) {
	    Tcl_FSDeleteFile(tempFile);
	    Tcl_DecrRefCount(tempFile);
	    tempFile = NULL;
	}
	res = Tcl_FSUnregister(&simpleFilesystem);
	msg = (res == TCL_OK) ? "unregistered" : "failed";
	simpleInterpPtr = NULL;
    }
    Tcl_SetResult(interp, msg, TCL_VOLATILE);
    return res;
}

/* 
 * Treats a file name 'simplefs:/foo' by copying the file 'foo'
 * in the current (native) directory to a temporary native file,
 * and then returns that native file.
 */
static Tcl_Obj*
SimpleCopy(pathPtr)
    Tcl_Obj *pathPtr;                   /* Name of file to copy. */
{
    int res;
    CONST char *str;
    Tcl_Obj *origPtr;
    Tcl_Obj *tempPtr;









    tempPtr = TclpTempFileName();
    Tcl_IncrRefCount(tempPtr);






















    /* 
     * We assume the same name in the current directory is ok.
     */
    str = Tcl_GetString(pathPtr);

    origPtr = Tcl_NewStringObj(str+10,-1);
    Tcl_IncrRefCount(origPtr);











    res = TclCrossFilesystemCopy(simpleInterpPtr, origPtr, tempPtr);
    Tcl_DecrRefCount(origPtr);

    if (res != TCL_OK) {
	Tcl_FSDeleteFile(tempPtr);
	Tcl_DecrRefCount(tempPtr);
	return NULL;
    }
    return tempPtr;
}

static Tcl_Channel
SimpleOpenFileChannel(interp, pathPtr, mode, permissions)
    Tcl_Interp *interp;                 /* Interpreter for error reporting;
					 * can be NULL. */
    Tcl_Obj *pathPtr;                   /* Name of file to open. */







<

<
<
<
<
<


<






|
|
<


|


|


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



|
>
|

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







6357
6358
6359
6360
6361
6362
6363

6364





6365
6366

6367
6368
6369
6370
6371
6372
6373
6374

6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391
6392
6393
6394
6395
6396
6397
6398
6399
6400
6401
6402
6403
6404
6405
6406
6407
6408
6409
6410
6411
6412
6413
6414
6415
6416
6417
6418
6419
6420
6421
6422
6423
6424
6425
6426
6427
6428
6429
6430
6431
6432
6433
6434


6435

6436
6437
6438


6439
6440
6441
6442
6443
6444
6445
    }
    if (Tcl_GetBooleanFromObj(interp, objv[1], &boolVal) != TCL_OK) {
	return TCL_ERROR;
    }
    if (boolVal) {
	res = Tcl_FSRegister((ClientData)interp, &simpleFilesystem);
	msg = (res == TCL_OK) ? "registered" : "failed";

    } else {





	res = Tcl_FSUnregister(&simpleFilesystem);
	msg = (res == TCL_OK) ? "unregistered" : "failed";

    }
    Tcl_SetResult(interp, msg, TCL_VOLATILE);
    return res;
}

/* 
 * Treats a file name 'simplefs:/foo' by using the file 'foo'
 * in the current (native) directory.

 */
static Tcl_Obj*
SimpleRedirect(pathPtr)
    Tcl_Obj *pathPtr;                   /* Name of file to copy. */
{
    int len;
    CONST char *str;
    Tcl_Obj *origPtr;

    /* 
     * We assume the same name in the current directory is ok.
     */
    str = Tcl_GetStringFromObj(pathPtr, &len);
    if (len < 10 || strncmp(str, "simplefs:/", 10)) {
	/* Probably shouldn't ever reach here */
	Tcl_IncrRefCount(pathPtr);
	return pathPtr;
    } 
    origPtr = Tcl_NewStringObj(str+10,-1);
    Tcl_IncrRefCount(origPtr);
    return origPtr;
}

static int
SimpleMatchInDirectory(interp, resultPtr, dirPtr, pattern, types)
    Tcl_Interp *interp;		/* Interpreter for error
				 * messages. */
    Tcl_Obj *resultPtr;		/* Object to lappend results. */
    Tcl_Obj *dirPtr;	        /* Contains path to directory to search. */
    CONST char *pattern;	/* Pattern to match against. */
    Tcl_GlobTypeData *types;	/* Object containing list of acceptable types.
				 * May be NULL. */
{
    int res;
    Tcl_Obj *origPtr;
    Tcl_Obj *resPtr;

    /* We only provide a new volume, therefore no mounts at all */
    if (types != NULL && types->type & TCL_GLOB_TYPE_MOUNT) {
	return TCL_OK;
    }
    
    /* 
     * We assume the same name in the current directory is ok.
     */
    resPtr = Tcl_NewObj();
    Tcl_IncrRefCount(resPtr);
    origPtr = SimpleRedirect(dirPtr);
    Tcl_IncrRefCount(origPtr);
    res = Tcl_FSMatchInDirectory(interp, resPtr, origPtr, pattern, types);
    if (res == TCL_OK) {
	int gLength, j;
	Tcl_ListObjLength(NULL, resPtr, &gLength);
	for (j = 0; j < gLength; j++) {
	    Tcl_Obj *gElt, *nElt;
	    Tcl_ListObjIndex(NULL, resPtr, j, &gElt);
	    nElt = Tcl_NewStringObj("simplefs:/",10);
	    Tcl_AppendObjToObj(nElt, gElt);
	    Tcl_ListObjAppendElement(NULL, resultPtr, nElt);
	}


    }

    Tcl_DecrRefCount(origPtr);
    Tcl_DecrRefCount(resPtr);
    return res;


}

static Tcl_Channel
SimpleOpenFileChannel(interp, pathPtr, mode, permissions)
    Tcl_Interp *interp;                 /* Interpreter for error reporting;
					 * can be NULL. */
    Tcl_Obj *pathPtr;                   /* Name of file to open. */
6364
6365
6366
6367
6368
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391
6392
6393
6394
6395
6396
6397



6398
6399
6400
6401
6402
6403
6404
6405

6406
6407
6408
6409
6410
6411
6412
6413
6414
6415
6416
6417
6418
6419
6420
6421
6422
    
    if ((mode != 0) && !(mode & O_RDONLY)) {
	Tcl_AppendResult(interp, "read-only", 
		(char *) NULL);
	return NULL;
    }
    
    tempPtr = SimpleCopy(pathPtr);
    
    if (tempPtr == NULL) {
	return NULL;
    }
    
    chan = Tcl_FSOpenFileChannel(interp, tempPtr, "r", permissions);

    if (tempFile != NULL) {
        Tcl_FSDeleteFile(tempFile);
	Tcl_DecrRefCount(tempFile);
	tempFile = NULL;
    }
    /* 
     * Store file pointer in this global variable so we can delete
     * it later 
     */
    tempFile = tempPtr;
    return chan;
}

static int
SimpleAccess(pathPtr, mode)
    Tcl_Obj *pathPtr;		/* Path of file to access (in current CP). */
    int mode;                   /* Permission setting. */
{
    /* All files exist */



    return TCL_OK;
}

static int
SimpleStat(pathPtr, bufPtr)
    Tcl_Obj *pathPtr;		/* Path of file to stat (in current CP). */
    Tcl_StatBuf *bufPtr;	/* Filled with results of stat call. */
{

    Tcl_Obj *tempPtr = SimpleCopy(pathPtr);
    if (tempPtr == NULL) {
	/* We just pretend the file exists anyway */
	return TCL_OK;
    } else {
	int res = Tcl_FSStat(tempPtr, bufPtr);
	Tcl_FSDeleteFile(tempPtr);
	Tcl_DecrRefCount(tempPtr);
	return res;
    }
}

static Tcl_Obj*
SimpleListVolumes(void)
{
    /* Add one new volume */
    Tcl_Obj *retVal;







|
<
<
<
<



<
<
|
<
<
<
<
<
<
<








|
>
>
>
|







>
|
<
<
<
<
|
<
|
|
<







6453
6454
6455
6456
6457
6458
6459
6460




6461
6462
6463


6464







6465
6466
6467
6468
6469
6470
6471
6472
6473
6474
6475
6476
6477
6478
6479
6480
6481
6482
6483
6484
6485
6486




6487

6488
6489

6490
6491
6492
6493
6494
6495
6496
    
    if ((mode != 0) && !(mode & O_RDONLY)) {
	Tcl_AppendResult(interp, "read-only", 
		(char *) NULL);
	return NULL;
    }
    
    tempPtr = SimpleRedirect(pathPtr);




    
    chan = Tcl_FSOpenFileChannel(interp, tempPtr, "r", permissions);



    Tcl_DecrRefCount(tempPtr);







    return chan;
}

static int
SimpleAccess(pathPtr, mode)
    Tcl_Obj *pathPtr;		/* Path of file to access (in current CP). */
    int mode;                   /* Permission setting. */
{
    int res;
    Tcl_Obj *tempPtr = SimpleRedirect(pathPtr);
    res = Tcl_FSAccess(tempPtr, mode);
    Tcl_DecrRefCount(tempPtr);
    return res;
}

static int
SimpleStat(pathPtr, bufPtr)
    Tcl_Obj *pathPtr;		/* Path of file to stat (in current CP). */
    Tcl_StatBuf *bufPtr;	/* Filled with results of stat call. */
{
    int res;
    Tcl_Obj *tempPtr = SimpleRedirect(pathPtr);




    res = Tcl_FSStat(tempPtr, bufPtr);

    Tcl_DecrRefCount(tempPtr);
    return res;

}

static Tcl_Obj*
SimpleListVolumes(void)
{
    /* Add one new volume */
    Tcl_Obj *retVal;
6442
6443
6444
6445
6446
6447
6448











































































	    (void) Tcl_GetStringFromObj(objv[1], &len);
	}
	len = Tcl_NumUtfChars(Tcl_GetString(objv[1]), len);
	Tcl_SetObjResult(interp, Tcl_NewIntObj(len));
    }
    return TCL_OK;
}


















































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
6516
6517
6518
6519
6520
6521
6522
6523
6524
6525
6526
6527
6528
6529
6530
6531
6532
6533
6534
6535
6536
6537
6538
6539
6540
6541
6542
6543
6544
6545
6546
6547
6548
6549
6550
6551
6552
6553
6554
6555
6556
6557
6558
6559
6560
6561
6562
6563
6564
6565
6566
6567
6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584
6585
6586
6587
6588
6589
6590
6591
6592
6593
6594
6595
6596
6597
	    (void) Tcl_GetStringFromObj(objv[1], &len);
	}
	len = Tcl_NumUtfChars(Tcl_GetString(objv[1]), len);
	Tcl_SetObjResult(interp, Tcl_NewIntObj(len));
    }
    return TCL_OK;
}

/*
 * Used to do basic checks of the TCL_HASH_KEY_SYSTEM_HASH flag
 */
static int
TestHashSystemHashCmd(clientData, interp, objc, objv)
    ClientData clientData;
    Tcl_Interp *interp;
    int objc;
    Tcl_Obj *CONST objv[];
{
    static Tcl_HashKeyType hkType = {
	TCL_HASH_KEY_TYPE_VERSION, TCL_HASH_KEY_SYSTEM_HASH,
	NULL, NULL, NULL, NULL
    };
    Tcl_HashTable hash;
    Tcl_HashEntry *hPtr;
    int i, isNew, limit = 100;

    if (objc>1 && Tcl_GetIntFromObj(interp, objv[1], &limit)!=TCL_OK) {
	return TCL_ERROR;
    }

    Tcl_InitCustomHashTable(&hash, TCL_CUSTOM_TYPE_KEYS, &hkType);

    if (hash.numEntries != 0) {
	Tcl_AppendResult(interp, "non-zero initial size", NULL);
	Tcl_DeleteHashTable(&hash);
	return TCL_ERROR;
    }

    for (i=0 ; i<limit ; i++) {
	hPtr = Tcl_CreateHashEntry(&hash, (char *)i, &isNew);
	if (!isNew) {
	    Tcl_SetObjResult(interp, Tcl_NewIntObj(i));
	    Tcl_AppendToObj(Tcl_GetObjResult(interp)," creation problem",-1);
	    Tcl_DeleteHashTable(&hash);
	    return TCL_ERROR;
	}
	Tcl_SetHashValue(hPtr, (ClientData) (i+42));
    }

    if (hash.numEntries != limit) {
	Tcl_AppendResult(interp, "unexpected maximal size", NULL);
	Tcl_DeleteHashTable(&hash);
	return TCL_ERROR;
    }

    for (i=0 ; i<limit ; i++) {
	hPtr = Tcl_FindHashEntry(&hash, (char *)i);
	if (hPtr == NULL) {
	    Tcl_SetObjResult(interp, Tcl_NewIntObj(i));
	    Tcl_AppendToObj(Tcl_GetObjResult(interp)," lookup problem",-1);
	    Tcl_DeleteHashTable(&hash);
	    return TCL_ERROR;
	}
	if ((int)(Tcl_GetHashValue(hPtr)) != i+42) {
	    Tcl_SetObjResult(interp, Tcl_NewIntObj(i));
	    Tcl_AppendToObj(Tcl_GetObjResult(interp)," value problem",-1);
	    Tcl_DeleteHashTable(&hash);
	    return TCL_ERROR;
	}
	Tcl_DeleteHashEntry(hPtr);
    }

    if (hash.numEntries != 0) {
	Tcl_AppendResult(interp, "non-zero final size", NULL);
	Tcl_DeleteHashTable(&hash);
	return TCL_ERROR;
    }

    Tcl_DeleteHashTable(&hash);
    Tcl_AppendResult(interp, "OK", NULL);
    return TCL_OK;
}
Changes to generic/tclThreadAlloc.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * tclThreadAlloc.c --
 *
 *	This is a very fast storage allocator for used with threads (designed
 *	avoid lock contention).  The basic strategy is to allocate memory in
 *  	fixed size blocks from block caches.
 *
 * The Initial Developer of the Original Code is America Online, Inc.
 * Portions created by AOL are Copyright (C) 1999 America Online, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclThreadAlloc.c,v 1.6 2003/05/10 04:28:59 mistachkin Exp $
 */

#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)

#include "tclInt.h"

#ifdef WIN32













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * tclThreadAlloc.c --
 *
 *	This is a very fast storage allocator for used with threads (designed
 *	avoid lock contention).  The basic strategy is to allocate memory in
 *  	fixed size blocks from block caches.
 *
 * The Initial Developer of the Original Code is America Online, Inc.
 * Portions created by AOL are Copyright (C) 1999 America Online, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclThreadAlloc.c,v 1.6.2.1 2004/02/07 05:48:01 dgp Exp $
 */

#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)

#include "tclInt.h"

#ifdef WIN32
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

/*
 * The following array specifies various per-bucket
 * limits and locks.  The values are statically initialized
 * to avoid calculating them repeatedly.
 */

struct binfo {
    size_t blocksize;	/* Bucket blocksize. */
    int maxblocks;	/* Max blocks before move to share. */
    int nmove;		/* Num blocks to move to share. */
    Tcl_Mutex *lockPtr; /* Share bucket lock. */
} binfo[NBUCKETS] = {
    {   16, 1024, 512, NULL},
    {   32,  512, 256, NULL},







|







113
114
115
116
117
118
119
120
121
122
123
124
125
126
127

/*
 * The following array specifies various per-bucket
 * limits and locks.  The values are statically initialized
 * to avoid calculating them repeatedly.
 */

static struct {
    size_t blocksize;	/* Bucket blocksize. */
    int maxblocks;	/* Max blocks before move to share. */
    int nmove;		/* Num blocks to move to share. */
    Tcl_Mutex *lockPtr; /* Share bucket lock. */
} binfo[NBUCKETS] = {
    {   16, 1024, 512, NULL},
    {   32,  512, 256, NULL},
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
     * Get this thread's cache, allocating if necessary.
     */

    cachePtr = TclpGetAllocCache();
    if (cachePtr == NULL) {
    	cachePtr = calloc(1, sizeof(Cache));
    	if (cachePtr == NULL) {
	    panic("alloc: could not allocate new cache");
    	}
    	Tcl_MutexLock(listLockPtr);
    	cachePtr->nextPtr = firstCachePtr;
    	firstCachePtr = cachePtr;
    	Tcl_MutexUnlock(listLockPtr);
    	cachePtr->owner = Tcl_GetCurrentThread();
	TclpSetAllocCache(cachePtr);







|







205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
     * Get this thread's cache, allocating if necessary.
     */

    cachePtr = TclpGetAllocCache();
    if (cachePtr == NULL) {
    	cachePtr = calloc(1, sizeof(Cache));
    	if (cachePtr == NULL) {
	    Tcl_Panic("alloc: could not allocate new cache");
    	}
    	Tcl_MutexLock(listLockPtr);
    	cachePtr->nextPtr = firstCachePtr;
    	firstCachePtr = cachePtr;
    	Tcl_MutexUnlock(listLockPtr);
    	cachePtr->owner = Tcl_GetCurrentThread();
	TclpSetAllocCache(cachePtr);
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
	    MoveObjs(sharedPtr, cachePtr, nmove);
	}
    	Tcl_MutexUnlock(objLockPtr);
	if (cachePtr->nobjs == 0) {
	    cachePtr->nobjs = nmove = NOBJALLOC;
	    newObjsPtr = malloc(sizeof(Tcl_Obj) * nmove);
	    if (newObjsPtr == NULL) {
		panic("alloc: could not allocate %d new objects", nmove);
	    }
	    while (--nmove >= 0) {
		objPtr = &newObjsPtr[nmove];
		objPtr->internalRep.otherValuePtr = cachePtr->firstObjPtr;
		cachePtr->firstObjPtr = objPtr;
	    }
	}







|







531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
	    MoveObjs(sharedPtr, cachePtr, nmove);
	}
    	Tcl_MutexUnlock(objLockPtr);
	if (cachePtr->nobjs == 0) {
	    cachePtr->nobjs = nmove = NOBJALLOC;
	    newObjsPtr = malloc(sizeof(Tcl_Obj) * nmove);
	    if (newObjsPtr == NULL) {
		Tcl_Panic("alloc: could not allocate %d new objects", nmove);
	    }
	    while (--nmove >= 0) {
		objPtr = &newObjsPtr[nmove];
		objPtr->internalRep.otherValuePtr = cachePtr->firstObjPtr;
		cachePtr->firstObjPtr = objPtr;
	    }
	}
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752

    blockPtr = (((Block *) ptr) - 1);
    if (blockPtr->b_magic1 != MAGIC
#if RCHECK
	|| ((unsigned char *) ptr)[blockPtr->b_reqsize] != MAGIC
#endif
	|| blockPtr->b_magic2 != MAGIC) {
	panic("alloc: invalid block: %p: %x %x %x\n",
	    blockPtr, blockPtr->b_magic1, blockPtr->b_magic2,
	    ((unsigned char *) ptr)[blockPtr->b_reqsize]);
    }
    return blockPtr;
}









|







738
739
740
741
742
743
744
745
746
747
748
749
750
751
752

    blockPtr = (((Block *) ptr) - 1);
    if (blockPtr->b_magic1 != MAGIC
#if RCHECK
	|| ((unsigned char *) ptr)[blockPtr->b_reqsize] != MAGIC
#endif
	|| blockPtr->b_magic2 != MAGIC) {
	Tcl_Panic("alloc: invalid block: %p: %x %x %x\n",
	    blockPtr, blockPtr->b_magic1, blockPtr->b_magic2,
	    ((unsigned char *) ptr)[blockPtr->b_reqsize]);
    }
    return blockPtr;
}


Changes to generic/tclTimer.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclTimer.c --
 *
 *	This file provides timer event management facilities for Tcl,
 *	including the "after" command.
 *
 * Copyright (c) 1997 by Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclTimer.c,v 1.6.4.1 2003/05/22 19:12:07 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * For each timer callback that's pending there is one record of the following











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclTimer.c --
 *
 *	This file provides timer event management facilities for Tcl,
 *	including the "after" command.
 *
 * Copyright (c) 1997 by Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclTimer.c,v 1.6.4.2 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * For each timer callback that's pending there is one record of the following
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
 	    Tcl_ListObjAppendElement(interp, resultListPtr, afterPtr->commandPtr);
 	    Tcl_ListObjAppendElement(interp, resultListPtr, Tcl_NewStringObj(
 		(afterPtr->token == NULL) ? "idle" : "timer", -1));
	    Tcl_SetObjResult(interp, resultListPtr);
	    break;
	}
	default: {
	    panic("Tcl_AfterObjCmd: bad subcommand index to afterSubCmds");
	}
    }
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------







|







932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
 	    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/tclTrace.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclTrace.c --
 *
 *	This file contains code to handle most trace management.
 *
 * Copyright (c) 1987-1993 The Regents of the University of California.
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 Scriptics Corporation.
 * Copyright (c) 2002 ActiveState Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclTrace.c,v 1.2.2.4 2003/10/16 02:28:02 dgp Exp $
 */

#include "tclInt.h"

/*
 * Structure used to hold information about variable traces:
 */













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclTrace.c --
 *
 *	This file contains code to handle most trace management.
 *
 * Copyright (c) 1987-1993 The Regents of the University of California.
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 Scriptics Corporation.
 * Copyright (c) 2002 ActiveState Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclTrace.c,v 1.2.2.5 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"

/*
 * Structure used to hold information about variable traces:
 */
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
		/* Append trace operation */
		if (flags & TCL_TRACE_EXEC_DIRECT) {
		    Tcl_DStringAppendElement(&cmd, "leave");
		} else {
		    Tcl_DStringAppendElement(&cmd, "leavestep");
		}
	    } else {
		panic("TraceExecutionProc: bad flag combination");
	    }
	    
	    /*
	     * Execute the command.  Save the interp's result used for
	     * the command, including the value of iPtr->returnOpts which
	     * may be modified when Tcl_Eval is invoked.  We discard any
	     * object result the command returns.







|







1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
		/* Append trace operation */
		if (flags & TCL_TRACE_EXEC_DIRECT) {
		    Tcl_DStringAppendElement(&cmd, "leave");
		} else {
		    Tcl_DStringAppendElement(&cmd, "leavestep");
		}
	    } else {
		Tcl_Panic("TraceExecutionProc: bad flag combination");
	    }
	    
	    /*
	     * Execute the command.  Save the interp's result used for
	     * the command, including the value of iPtr->returnOpts which
	     * may be modified when Tcl_Eval is invoked.  We discard any
	     * object result the command returns.
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
	    "trace", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
    if (varPtr == NULL) {
	return TCL_ERROR;
    }

    /*
     * Check for a nonsense flag combination.  Note that this is a
     * panic() because there should be no code path that ever sets
     * both flags.
     */
    if ((flags&TCL_TRACE_RESULT_DYNAMIC) && (flags&TCL_TRACE_RESULT_OBJECT)) {
	panic("bad result flag combination");
    }

    /*
     * Set up trace information.
     */

    flagMask = TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS | 







|



|







2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
	    "trace", /*createPart1*/ 1, /*createPart2*/ 1, &arrayPtr);
    if (varPtr == NULL) {
	return TCL_ERROR;
    }

    /*
     * Check for a nonsense flag combination.  Note that this is a
     * Tcl_Panic() because there should be no code path that ever sets
     * both flags.
     */
    if ((flags&TCL_TRACE_RESULT_DYNAMIC) && (flags&TCL_TRACE_RESULT_OBJECT)) {
	Tcl_Panic("bad result flag combination");
    }

    /*
     * Set up trace information.
     */

    flagMask = TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS | 
Changes to generic/tclVar.c.
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclVar.c,v 1.73.2.2 2003/07/07 20:23:38 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * The strings below are used to indicate what went wrong when a







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 * Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclVar.c,v 1.73.2.3 2004/02/07 05:48:01 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

/*
 * The strings below are used to indicate what went wrong when a
599
600
601
602
603
604
605



606

607
608
609
610
611
612
613
614
/*
 * This flag bit should not interfere with TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
 * or TCL_LEAVE_ERR_MSG; it signals that the variable lookup is performed for 
 * upvar (or similar) purposes, with slightly different rules:
 *   - Bug #696893 - variable is either proc-local or in the current
 *     namespace; never follow the second (global) resolution path 
 *   - Bug #631741 - do not use special namespace or interp resolvers



 */

#define LOOKUP_FOR_UPVAR 0x400

/*
 *----------------------------------------------------------------------
 *
 * TclLookupSimpleVar --
 *
 *	This procedure is used by to locate a simple variable (i.e., not







>
>
>

>
|







599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
/*
 * This flag bit should not interfere with TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
 * or TCL_LEAVE_ERR_MSG; it signals that the variable lookup is performed for 
 * upvar (or similar) purposes, with slightly different rules:
 *   - Bug #696893 - variable is either proc-local or in the current
 *     namespace; never follow the second (global) resolution path 
 *   - Bug #631741 - do not use special namespace or interp resolvers
 *
 * It should also not collide with the (deprecated) TCL_PARSE_PART1 flag
 * (Bug #835020)
 */

#define LOOKUP_FOR_UPVAR 0x40000

/*
 *----------------------------------------------------------------------
 *
 * TclLookupSimpleVar --
 *
 *	This procedure is used by to locate a simple variable (i.e., not
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
    }
    if (otherPtr == NULL) {
	return TCL_ERROR;
    }

    if (index >= 0) {
	if (!varFramePtr->isProcCallFrame) {
	    panic("ObjMakeUpvar called with an index outside from a proc.\n");
	}
	varPtr = &(varFramePtr->compiledLocals[index]);
    } else {
	/*
	 * Check that we are not trying to create a namespace var linked to
	 * a local variable in a procedure. If we allowed this, the local
	 * variable in the shorter-lived procedure frame could go away







|







3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
    }
    if (otherPtr == NULL) {
	return TCL_ERROR;
    }

    if (index >= 0) {
	if (!varFramePtr->isProcCallFrame) {
	    Tcl_Panic("ObjMakeUpvar called with an index outside from a proc.\n");
	}
	varPtr = &(varFramePtr->compiledLocals[index]);
    } else {
	/*
	 * Check that we are not trying to create a namespace var linked to
	 * a local variable in a procedure. If we allowed this, the local
	 * variable in the shorter-lived procedure frame could go away
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
    int len1, len2, totalLen;

    if (arrayPtr == NULL) {
	/*
	 * This is a parsed scalar name: what is it
	 * doing here?
	 */
	panic("ERROR: scalar parsedVarName without a string rep.\n");
    }
    part1 = Tcl_GetStringFromObj(arrayPtr, &len1);
    len2 = strlen(part2);
	
    totalLen = len1 + len2 + 2;
    p = ckalloc((unsigned int) totalLen + 1);
    objPtr->bytes = p;







|







4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
    int len1, len2, totalLen;

    if (arrayPtr == NULL) {
	/*
	 * This is a parsed scalar name: what is it
	 * doing here?
	 */
	Tcl_Panic("ERROR: scalar parsedVarName without a string rep.\n");
    }
    part1 = Tcl_GetStringFromObj(arrayPtr, &len1);
    len2 = strlen(part2);
	
    totalLen = len1 + len2 + 2;
    p = ckalloc((unsigned int) totalLen + 1);
    objPtr->bytes = p;
Changes to library/auto.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
# auto.tcl --
#
# utility procs formerly in init.tcl dealing with auto execution
# of commands and can be auto loaded themselves.
#
# RCS: @(#) $Id: auto.tcl,v 1.13 2003/03/19 21:57:40 dgp Exp $
#
# Copyright (c) 1991-1993 The Regents of the University of California.
# Copyright (c) 1994-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.
#





|







1
2
3
4
5
6
7
8
9
10
11
12
13
# auto.tcl --
#
# utility procs formerly in init.tcl dealing with auto execution
# of commands and can be auto loaded themselves.
#
# RCS: @(#) $Id: auto.tcl,v 1.13.2.1 2004/02/07 05:48:01 dgp Exp $
#
# Copyright (c) 1991-1993 The Regents of the University of California.
# Copyright (c) 1994-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.
#
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    append index "# Tcl autoload index file, version 2.0\n"
    append index "# This file is generated by the \"auto_mkindex\" command\n"
    append index "# and sourced to set up indexing information for one or\n"
    append index "# more commands.  Typically each line is a command that\n"
    append index "# sets an element in the auto_index array, where the\n"
    append index "# element name is the name of a command and the value is\n"
    append index "# a script that loads the command.\n\n"
    if {$args == ""} {
	set args *.tcl
    }

    auto_mkindex_parser::init
    foreach file [eval glob $args] {
        if {[catch {auto_mkindex_parser::mkindex $file} msg] == 0} {
            append index $msg
        } else {
            set code $errorCode
            set info $errorInfo
            cd $oldDir
            error $msg $info $code







|




|







174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    append index "# Tcl autoload index file, version 2.0\n"
    append index "# This file is generated by the \"auto_mkindex\" command\n"
    append index "# and sourced to set up indexing information for one or\n"
    append index "# more commands.  Typically each line is a command that\n"
    append index "# sets an element in the auto_index array, where the\n"
    append index "# element name is the name of a command and the value is\n"
    append index "# a script that loads the command.\n\n"
    if {[llength $args] == 0} {
	set args *.tcl
    }

    auto_mkindex_parser::init
    foreach file [glob {expand}$args] {
        if {[catch {auto_mkindex_parser::mkindex $file} msg] == 0} {
            append index $msg
        } else {
            set code $errorCode
            set info $errorInfo
            cd $oldDir
            error $msg $info $code
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
    append index "# Tcl autoload index file, version 2.0\n"
    append index "# This file is generated by the \"auto_mkindex\" command\n"
    append index "# and sourced to set up indexing information for one or\n"
    append index "# more commands.  Typically each line is a command that\n"
    append index "# sets an element in the auto_index array, where the\n"
    append index "# element name is the name of a command and the value is\n"
    append index "# a script that loads the command.\n\n"
    if {[string equal $args ""]} {
	set args *.tcl
    }
    foreach file [eval glob $args] {
	set f ""
	set error [catch {
	    set f [open $file]
	    while {[gets $f line] >= 0} {
		if {[regexp {^proc[ 	]+([^ 	]*)} $line match procName]} {
		    set procName [lindex [auto_qualify $procName "::"] 0]
		    append index "set [list auto_index($procName)]"







|


|







212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
    append index "# Tcl autoload index file, version 2.0\n"
    append index "# This file is generated by the \"auto_mkindex\" command\n"
    append index "# and sourced to set up indexing information for one or\n"
    append index "# more commands.  Typically each line is a command that\n"
    append index "# sets an element in the auto_index array, where the\n"
    append index "# element name is the name of a command and the value is\n"
    append index "# a script that loads the command.\n\n"
    if {[llength $args] == 0} {
	set args *.tcl
    }
    foreach file [glob {expand}$args] {
	set f ""
	set error [catch {
	    set f [open $file]
	    while {[gets $f line] >= 0} {
		if {[regexp {^proc[ 	]+([^ 	]*)} $line match procName]} {
		    set procName [lindex [auto_qualify $procName "::"] 0]
		    append index "set [list auto_index($procName)]"
Changes to library/dde/pkgIndex.tcl.
1

2
3
4
5
6
if {![package vsatisfies [package provide Tcl] 8]} {return}

if {[info exists ::tcl_platform(debug)]} {
    package ifneeded dde 1.2.5 [list load [file join $dir tcldde12g.dll] dde]
} else {
    package ifneeded dde 1.2.5 [list load [file join $dir tcldde12.dll] dde]
}

>

|

|

1
2
3
4
5
6
7
if {![package vsatisfies [package provide Tcl] 8]} {return}
if {[string compare $::tcl_platform(platform) windows]} {return}
if {[info exists ::tcl_platform(debug)]} {
    package ifneeded dde 1.3 [list load [file join $dir tcldde13g.dll] dde]
} else {
    package ifneeded dde 1.3 [list load [file join $dir tcldde13.dll] dde]
}
Changes to library/init.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
# init.tcl --
#
# Default system startup file for Tcl-based applications.  Defines
# "unknown" procedure and auto-load facilities.
#
# RCS: @(#) $Id: init.tcl,v 1.56.2.1 2003/10/16 02:28:02 dgp Exp $
#
# Copyright (c) 1991-1993 The Regents of the University of California.
# Copyright (c) 1994-1996 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.





|







1
2
3
4
5
6
7
8
9
10
11
12
13
# init.tcl --
#
# Default system startup file for Tcl-based applications.  Defines
# "unknown" procedure and auto-load facilities.
#
# RCS: @(#) $Id: init.tcl,v 1.56.2.2 2004/02/07 05:48:01 dgp Exp $
#
# Copyright (c) 1991-1993 The Regents of the University of California.
# Copyright (c) 1994-1996 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.
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
# Arguments: 
# action -              "renaming" or "copying" 
# src -			source directory
# dest -		destination directory
proc tcl::CopyDirectory {action src dest} {
    set nsrc [file normalize $src]
    set ndest [file normalize $dest]

    if {[string equal $action "renaming"]} {
	# Can't rename volumes.  We could give a more precise
	# error message here, but that would break the test suite.
	if {[lsearch -exact [file volumes] $nsrc] != -1} {
	    return -code error "error $action \"$src\" to\
	      \"$dest\": trying to rename a volume or move a directory\
	      into itself"
	}
    }
    if {[file exists $dest]} {
	if {$nsrc == $ndest} {
	    return -code error "error $action \"$src\" to\
	      \"$dest\": trying to rename a volume or move a directory\
	      into itself"
	}
	if {[string equal $action "copying"]} {






	    return -code error "error $action \"$src\" to\
	      \"$dest\": file already exists"
	} else {
	    # Depending on the platform, and on the current
	    # working directory, the directories '.', '..'
	    # can be returned in various combinations.  Anyway,
	    # if any other file is returned, we must signal an error.
	    set existing [glob -nocomplain -directory $dest * .*]
	    eval [list lappend existing] \







>
















>
>
>
>
>
>
|
|







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
# Arguments: 
# action -              "renaming" or "copying" 
# src -			source directory
# dest -		destination directory
proc tcl::CopyDirectory {action src dest} {
    set nsrc [file normalize $src]
    set ndest [file normalize $dest]

    if {[string equal $action "renaming"]} {
	# Can't rename volumes.  We could give a more precise
	# error message here, but that would break the test suite.
	if {[lsearch -exact [file volumes] $nsrc] != -1} {
	    return -code error "error $action \"$src\" to\
	      \"$dest\": trying to rename a volume or move a directory\
	      into itself"
	}
    }
    if {[file exists $dest]} {
	if {$nsrc == $ndest} {
	    return -code error "error $action \"$src\" to\
	      \"$dest\": trying to rename a volume or move a directory\
	      into itself"
	}
	if {[string equal $action "copying"]} {
	    # We used to throw an error here, but, looking more closely
	    # at the core copy code in tclFCmd.c, if the destination
	    # exists, then we should only call this function if -force
	    # is true, which means we just want to over-write.  So,
	    # the following code is now commented out.
	    # 
	    # return -code error "error $action \"$src\" to\
	    # \"$dest\": file already exists"
	} else {
	    # Depending on the platform, and on the current
	    # working directory, the directories '.', '..'
	    # can be returned in various combinations.  Anyway,
	    # if any other file is returned, we must signal an error.
	    set existing [glob -nocomplain -directory $dest * .*]
	    eval [list lappend existing] \
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
    # We will also be more generous to the file system and not
    # assume the hidden and non-hidden lists are non-overlapping.
    # 
    # On Unix 'hidden' files begin with '.'.  On other platforms
    # or filesystems hidden files may have other interpretations.
    set filelist [concat [glob -nocomplain -directory $src *] \
      [glob -nocomplain -directory $src -types hidden *]]
    
    foreach s [lsort -unique $filelist] {
	if {([file tail $s] != ".") && ([file tail $s] != "..")} {
	    file copy $s [file join $dest [file tail $s]]
	}
    }
    return
}







|


|




724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
    # We will also be more generous to the file system and not
    # assume the hidden and non-hidden lists are non-overlapping.
    # 
    # On Unix 'hidden' files begin with '.'.  On other platforms
    # or filesystems hidden files may have other interpretations.
    set filelist [concat [glob -nocomplain -directory $src *] \
      [glob -nocomplain -directory $src -types hidden *]]

    foreach s [lsort -unique $filelist] {
	if {([file tail $s] != ".") && ([file tail $s] != "..")} {
	    file copy -force $s [file join $dest [file tail $s]]
	}
    }
    return
}
Changes to library/msgcat/msgcat.tcl.
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
# msgcat.tcl --
#
#	This file defines various procedures which implement a
#	message catalog facility for Tcl programs.  It should be
#	loaded with the command "package require msgcat".
#
# Copyright (c) 1998-2000 by Ajuba Solutions.
# Copyright (c) 1998 by Mark Harrison.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# RCS: @(#) $Id: msgcat.tcl,v 1.17.4.1 2003/08/07 21:36:02 dgp Exp $

package require Tcl 8.2
# When the version number changes, be sure to update the pkgIndex.tcl file,
# and the installation directory in the Makefiles.
package provide msgcat 1.3.1

namespace eval msgcat {
    namespace export mc mcload mclocale mcmax mcmset mcpreferences mcset \
	    mcunknown

    # Records the current locale as passed to mclocale
    variable Locale ""












|




|







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
# msgcat.tcl --
#
#	This file defines various procedures which implement a
#	message catalog facility for Tcl programs.  It should be
#	loaded with the command "package require msgcat".
#
# Copyright (c) 1998-2000 by Ajuba Solutions.
# Copyright (c) 1998 by Mark Harrison.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# RCS: @(#) $Id: msgcat.tcl,v 1.17.4.2 2004/02/07 05:48:02 dgp Exp $

package require Tcl 8.2
# 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

namespace eval msgcat {
    namespace export mc mcload mclocale mcmax mcmset mcpreferences mcset \
	    mcunknown

    # Records the current locale as passed to mclocale
    variable Locale ""
230
231
232
233
234
235
236

237
238
239
240
241
242
243
	set Locale [string tolower [lindex $args 0]]
	set Loclist {}
	set word ""
	foreach part [split $Locale _] {
	    set word [string trimleft "${word}_${part}" _]
	    set Loclist [linsert $Loclist 0 $word]
	}

    }
    return $Locale
}

# msgcat::mcpreferences --
#
#	Fetch the list of locales used to look up strings, ordered from







>







230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
	set Locale [string tolower [lindex $args 0]]
	set Loclist {}
	set word ""
	foreach part [split $Locale _] {
	    set word [string trimleft "${word}_${part}" _]
	    set Loclist [linsert $Loclist 0 $word]
	}
	lappend Loclist {}
    }
    return $Locale
}

# msgcat::mcpreferences --
#
#	Fetch the list of locales used to look up strings, ordered from
264
265
266
267
268
269
270



271
272
273
274
275
276
277
#
# Results:
#	Returns the number of message catalogs that were loaded.

proc msgcat::mcload {langdir} {
    set x 0
    foreach p [mcpreferences] {



	set langfile [file join $langdir $p.msg]
	if {[file exists $langfile]} {
	    incr x
	    set fid [open $langfile "r"]
	    fconfigure $fid -encoding utf-8
            uplevel 1 [read $fid]
	    close $fid







>
>
>







265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
#
# Results:
#	Returns the number of message catalogs that were loaded.

proc msgcat::mcload {langdir} {
    set x 0
    foreach p [mcpreferences] {
	if { $p eq {} } {
	    set p ROOT
        }
	set langfile [file join $langdir $p.msg]
	if {[file exists $langfile]} {
	    incr x
	    set fid [open $langfile "r"]
	    fconfigure $fid -encoding utf-8
            uplevel 1 [read $fid]
	    close $fid
Changes to library/msgcat/pkgIndex.tcl.
1
2
if {![package vsatisfies [package provide Tcl] 8.2]} {return}
package ifneeded msgcat 1.3.1 [list source [file join $dir msgcat.tcl]]

|
1
2
if {![package vsatisfies [package provide Tcl] 8.2]} {return}
package ifneeded msgcat 1.4 [list source [file join $dir msgcat.tcl]]
Changes to library/package.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
# package.tcl --
#
# utility procs formerly in init.tcl which can be loaded on demand
# for package management.
#
# RCS: @(#) $Id: package.tcl,v 1.23.4.2 2003/10/16 02:28:02 dgp Exp $
#
# Copyright (c) 1991-1993 The Regents of the University of California.
# Copyright (c) 1994-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.
#





|







1
2
3
4
5
6
7
8
9
10
11
12
13
# package.tcl --
#
# utility procs formerly in init.tcl which can be loaded on demand
# for package management.
#
# RCS: @(#) $Id: package.tcl,v 1.23.4.3 2004/02/07 05:48:02 dgp Exp $
#
# Copyright (c) 1991-1993 The Regents of the University of California.
# Copyright (c) 1994-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.
#
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
    if {[llength $patternList] == 0} {
	set patternList [list "*.tcl" "*[info sharedlibextension]"]
    }

    set oldDir [pwd]
    cd $dir

    if {[catch {eval glob $patternList} fileList]} {
	global errorCode errorInfo
	cd $oldDir
	return -code error -errorcode $errorCode -errorinfo $errorInfo $fileList
    }
    foreach file $fileList {
	# For each file, figure out what commands and packages it provides.
	# To do this, create a child interpreter, load the file into the







|







136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
    if {[llength $patternList] == 0} {
	set patternList [list "*.tcl" "*[info sharedlibextension]"]
    }

    set oldDir [pwd]
    cd $dir

    if {[catch {glob {expand}$patternList} fileList]} {
	global errorCode errorInfo
	cd $oldDir
	return -code error -errorcode $errorCode -errorinfo $errorInfo $fileList
    }
    foreach file $fileList {
	# For each file, figure out what commands and packages it provides.
	# To do this, create a child interpreter, load the file into the
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
	    # Stub out the package command so packages can
	    # require other packages.

	    rename package __package_orig
	    proc package {what args} {
		switch -- $what {
		    require { return ; # ignore transitive requires }
		    default { eval __package_orig {$what} $args }
		}
	    }
	    proc tclPkgUnknown args {}
	    package unknown tclPkgUnknown

	    # Stub out the unknown command so package can call
	    # into each other during their initialilzation.







|







202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
	    # Stub out the package command so packages can
	    # require other packages.

	    rename package __package_orig
	    proc package {what args} {
		switch -- $what {
		    require { return ; # ignore transitive requires }
		    default { __package_orig $what {expand}$args }
		}
	    }
	    proc tclPkgUnknown args {}
	    package unknown tclPkgUnknown

	    # Stub out the unknown command so package can call
	    # into each other during their initialilzation.
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
		# we need to track command defined by each package even in
		# the -direct case, because they are needed internally by
		# the "partial pkgIndex.tcl" step above.

		proc ::tcl::GetAllNamespaces {{root ::}} {
		    set list $root
		    foreach ns [namespace children $root] {
			eval lappend list [::tcl::GetAllNamespaces $ns]
		    }
		    return $list
		}

		# init the list of existing namespaces, packages, commands

		foreach ::tcl::x [::tcl::GetAllNamespaces] {







|







257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
		# we need to track command defined by each package even in
		# the -direct case, because they are needed internally by
		# the "partial pkgIndex.tcl" step above.

		proc ::tcl::GetAllNamespaces {{root ::}} {
		    set list $root
		    foreach ns [namespace children $root] {
			lappend list {expand}[::tcl::GetAllNamespaces $ns]
		    }
		    return $list
		}

		# init the list of existing namespaces, packages, commands

		foreach ::tcl::x [::tcl::GetAllNamespaces] {
Changes to library/reg/pkgIndex.tcl.
1

2
3
4
5
6
7
8
if {![package vsatisfies [package provide Tcl] 8]} {return}

if {[info exists ::tcl_platform(debug)]} {
    package ifneeded registry 1.1.2 \
            [list load [file join $dir tclreg11g.dll] registry]
} else {
    package ifneeded registry 1.1.2 \
            [list load [file join $dir tclreg11.dll] registry]
}

>

|


|


1
2
3
4
5
6
7
8
9
if {![package vsatisfies [package provide Tcl] 8]} {return}
if {[string compare $::tcl_platform(platform) windows]} {return}
if {[info exists ::tcl_platform(debug)]} {
    package ifneeded registry 1.1.3 \
            [list load [file join $dir tclreg11g.dll] registry]
} else {
    package ifneeded registry 1.1.3 \
            [list load [file join $dir tclreg11.dll] registry]
}
Changes to library/safe.tcl.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# See the safe.n man page for details.
#
# Copyright (c) 1996-1997 Sun Microsystems, Inc.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: safe.tcl,v 1.10.2.1 2003/08/07 21:36:01 dgp Exp $

#
# The implementation is based on namespaces. These naming conventions
# are followed:
# Private procs starts with uppercase.
# Public  procs are exported and starts with lowercase
#







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# See the safe.n man page for details.
#
# Copyright (c) 1996-1997 Sun Microsystems, Inc.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: safe.tcl,v 1.10.2.2 2004/02/07 05:48:02 dgp Exp $

#
# The implementation is based on namespaces. These naming conventions
# are followed:
# Private procs starts with uppercase.
# Public  procs are exported and starts with lowercase
#
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
	set hookname [DeleteHookName $slave]
	if {[Exists $hookname]} {
	    set hook [Set $hookname]
	    if {![::tcl::Lempty $hook]} {
		# remove the hook now, otherwise if the hook
		# calls us somehow, we'll loop
		Unset $hookname
		if {[catch {eval $hook [list $slave]} err]} {
		    Log $slave "Delete hook error ($err)"
		}
	    }
	}

	# Discard the global array of state associated with the slave, and
	# delete the interpreter.







|







521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
	set hookname [DeleteHookName $slave]
	if {[Exists $hookname]} {
	    set hook [Set $hookname]
	    if {![::tcl::Lempty $hook]} {
		# remove the hook now, otherwise if the hook
		# calls us somehow, we'll loop
		Unset $hookname
		if {[catch {{expand}$hook $slave} err]} {
		    Log $slave "Delete hook error ($err)"
		}
	    }
	}

	# Discard the global array of state associated with the slave, and
	# delete the interpreter.
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
    }
    # Run some code at the namespace toplevel
    proc Toplevel {args} {
	namespace eval [namespace current] $args
    }
    # set/get values
    proc Set {args} {
	eval [list Toplevel set] $args
    }
    # lappend on toplevel vars
    proc Lappend {args} {
	eval [list Toplevel lappend] $args
    }
    # unset a var/token (currently just an global level eval)
    proc Unset {args} {
	eval [list Toplevel unset] $args
    }
    # test existance 
    proc Exists {varname} {
	Toplevel info exists $varname
    }
    # short cut for access path getting
    proc GetAccessPath {slave} {







|



|



|







632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
    }
    # Run some code at the namespace toplevel
    proc Toplevel {args} {
	namespace eval [namespace current] $args
    }
    # set/get values
    proc Set {args} {
	Toplevel set {expand}$args
    }
    # lappend on toplevel vars
    proc Lappend {args} {
	Toplevel lappend {expand}$args
    }
    # unset a var/token (currently just an global level eval)
    proc Unset {args} {
	Toplevel unset {expand}$args
    }
    # test existance 
    proc Exists {varname} {
	Toplevel info exists $varname
    }
    # short cut for access path getting
    proc GetAccessPath {slave} {
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701


    # Log eventually log an error
    # to enable error logging, set Log to {puts stderr} for instance
    proc Log {slave msg {type ERROR}} {
	variable Log
	if {[info exists Log] && [llength $Log]} {
	    eval $Log [list "$type for slave $slave : $msg"]
	}
    }


    # file name control (limit access to files/ressources that should be
    # a valid tcl source file)
    proc CheckFileName {slave file} {







|







687
688
689
690
691
692
693
694
695
696
697
698
699
700
701


    # Log eventually log an error
    # to enable error logging, set Log to {puts stderr} for instance
    proc Log {slave msg {type ERROR}} {
	variable Log
	if {[info exists Log] && [llength $Log]} {
	    {expand}$Log "$type for slave $slave : $msg"
	}
    }


    # file name control (limit access to files/ressources that should be
    # a valid tcl source file)
    proc CheckFileName {slave file} {
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866

    # This procedure enables access from a safe interpreter to only a subset of
    # the subcommands of a command:

    proc Subset {slave command okpat args} {
	set subcommand [lindex $args 0]
	if {[regexp $okpat $subcommand]} {
	    return [eval [list $command $subcommand] [lrange $args 1 end]]
	}
	set msg "not allowed to invoke subcommand $subcommand of $command"
	Log $slave $msg
	error $msg
    }

    # This procedure installs an alias in a slave that invokes "safesubset"







|







852
853
854
855
856
857
858
859
860
861
862
863
864
865
866

    # This procedure enables access from a safe interpreter to only a subset of
    # the subcommands of a command:

    proc Subset {slave command okpat args} {
	set subcommand [lindex $args 0]
	if {[regexp $okpat $subcommand]} {
	    return [$command $subcommand {expand}[lrange $args 1 end]]
	}
	set msg "not allowed to invoke subcommand $subcommand of $command"
	Log $slave $msg
	error $msg
    }

    # This procedure installs an alias in a slave that invokes "safesubset"
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902

	set argc [llength $args]

	set okpat "^(name.*|convert.*)\$"
	set subcommand [lindex $args 0]

	if {[regexp $okpat $subcommand]} {
	    return [eval ::interp invokehidden $slave encoding $subcommand \
		    [lrange $args 1 end]]
	}

	if {[string match $subcommand system]} {
	    if {$argc == 1} {
		# passed all the tests , lets source it:
		if {[catch {::interp invokehidden \
			$slave encoding system} msg]} {







|
|







887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902

	set argc [llength $args]

	set okpat "^(name.*|convert.*)\$"
	set subcommand [lindex $args 0]

	if {[regexp $okpat $subcommand]} {
	    return [::interp invokehidden $slave encoding $subcommand \
		    {expand}[lrange $args 1 end]]
	}

	if {[string match $subcommand system]} {
	    if {$argc == 1} {
		# passed all the tests , lets source it:
		if {[catch {::interp invokehidden \
			$slave encoding system} msg]} {
Changes to library/tcltest/pkgIndex.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex -direct" command
# and sourced either when an application starts up or
# by a "package unknown" script.  It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands.  When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.

if {![package vsatisfies [package provide Tcl] 8.3]} {return}
package ifneeded tcltest 2.2.4 [list source [file join $dir tcltest.tcl]]











|
1
2
3
4
5
6
7
8
9
10
11
12
# Tcl package index file, version 1.1
# This file is generated by the "pkg_mkIndex -direct" command
# and sourced either when an application starts up or
# by a "package unknown" script.  It invokes the
# "package ifneeded" command to set up package-related
# information so that packages will be loaded automatically
# in response to "package require" commands.  When this
# script is sourced, the variable $dir must contain the
# full path name of this file's directory.

if {![package vsatisfies [package provide Tcl] 8.3]} {return}
package ifneeded tcltest 2.2.5 [list source [file join $dir tcltest.tcl]]
Changes to library/tcltest/tcltest.tcl.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#
# Copyright (c) 1994-1997 Sun Microsystems, Inc.
# Copyright (c) 1998-1999 by Scriptics Corporation.
# Copyright (c) 2000 by Ajuba Solutions
# Contributions from Don Porter, NIST, 2002.  (not subject to US copyright)
# All rights reserved.
#
# RCS: @(#) $Id: tcltest.tcl,v 1.82.2.1 2003/08/07 21:36:03 dgp Exp $

package require Tcl 8.3		;# uses [glob -directory]
namespace eval tcltest {

    # When the version number changes, be sure to update the pkgIndex.tcl file,
    # and the install directory in the Makefiles.  When the minor version
    # changes (new feature) be sure to update the man page as well.
    variable Version 2.2.4

    # Compatibility support for dumb variables defined in tcltest 1
    # Do not use these.  Call [package provide Tcl] and [info patchlevel]
    # yourself.  You don't need tcltest to wrap it for you.
    variable version [package provide Tcl]
    variable patchLevel [info patchlevel]








|







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#
# Copyright (c) 1994-1997 Sun Microsystems, Inc.
# Copyright (c) 1998-1999 by Scriptics Corporation.
# Copyright (c) 2000 by Ajuba Solutions
# Contributions from Don Porter, NIST, 2002.  (not subject to US copyright)
# All rights reserved.
#
# RCS: @(#) $Id: tcltest.tcl,v 1.82.2.2 2004/02/07 05:48:02 dgp Exp $

package require Tcl 8.3		;# uses [glob -directory]
namespace eval tcltest {

    # When the version number changes, be sure to update the pkgIndex.tcl file,
    # and the install directory in the Makefiles.  When the minor version
    # changes (new feature) be sure to update the man page as well.
    variable Version 2.2.5

    # Compatibility support for dumb variables defined in tcltest 1
    # Do not use these.  Call [package provide Tcl] and [info patchlevel]
    # yourself.  You don't need tcltest to wrap it for you.
    variable version [package provide Tcl]
    variable patchLevel [info patchlevel]

1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
	exit 1
    }

    if {[llength $flagArray] == 0} {
	RemoveAutoConfigureTraces
    } else {
	set args $flagArray
	while {[llength $args] && [catch {eval configure $args} msg]} {

	    # Something went wrong parsing $args for tcltest options
	    # Check whether the problem is "unknown option"
	    if {[regexp {^unknown option (\S+):} $msg -> option]} {
		# Could be this is an option the Hook knows about
		set moreOptions [processCmdLineArgsAddFlagsHook]
		if {[lsearch -exact $moreOptions $option] == -1} {







|







1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
	exit 1
    }

    if {[llength $flagArray] == 0} {
	RemoveAutoConfigureTraces
    } else {
	set args $flagArray
	while {[llength $args]>1 && [catch {eval configure $args} msg]} {

	    # Something went wrong parsing $args for tcltest options
	    # Check whether the problem is "unknown option"
	    if {[regexp {^unknown option (\S+):} $msg -> option]} {
		# Could be this is an option the Hook knows about
		set moreOptions [processCmdLineArgsAddFlagsHook]
		if {[lsearch -exact $moreOptions $option] == -1} {
1445
1446
1447
1448
1449
1450
1451





1452
1453
1454
1455
1456
1457
1458

	    # To recover, find that unknown option and remove up to it.
	    # then retry
	    while {![string equal [lindex $args 0] $option]} {
		set args [lrange $args 2 end]
	    }
	    set args [lrange $args 2 end]





	}
    }

    # Call the hook
    array set flag $flagArray
    processCmdLineArgsHook [array get flag]
    return







>
>
>
>
>







1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463

	    # To recover, find that unknown option and remove up to it.
	    # then retry
	    while {![string equal [lindex $args 0] $option]} {
		set args [lrange $args 2 end]
	    }
	    set args [lrange $args 2 end]
	}
	if {[llength $args] == 1} {
	    puts [errorChannel] \
		    "missing value for option [lindex $args 0]"
	    exit 1
	}
    }

    # Call the hook
    array set flag $flagArray
    processCmdLineArgsHook [array get flag]
    return
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
	}

	if {[file exists [file join [workingDirectory] core]]} {
	    if {[preserveCore] > 1} {
		puts "rename core file (> 1)"
		puts [outputChannel] "produced core file! \
			Moving file to: \
			[file join [temporaryDirectory] core-$name]"
		catch {file rename -force \
			[file join [workingDirectory] core] \
			[file join [temporaryDirectory] core-$name]
		} msg
		if {[string length $msg] > 0} {
		    PrintError "Problem renaming file: $msg"
		}
	    } else {
		# Print a message if there is a core file and (1) there
		# previously wasn't one or (2) the new one is different







|


|







2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
	}

	if {[file exists [file join [workingDirectory] core]]} {
	    if {[preserveCore] > 1} {
		puts "rename core file (> 1)"
		puts [outputChannel] "produced core file! \
			Moving file to: \
			[file join [temporaryDirectory] core-$testFileName]"
		catch {file rename -force \
			[file join [workingDirectory] core] \
			[file join [temporaryDirectory] core-$testFileName]
		} msg
		if {[string length $msg] > 0} {
		    PrintError "Problem renaming file: $msg"
		}
	    } else {
		# Print a message if there is a core file and (1) there
		# previously wasn't one or (2) the new one is different
Changes to mac/tclMacChan.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclMacChan.c
 *
 *	Channel drivers for Macintosh channels for the
 *	console fds.
 *
 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclMacChan.c,v 1.21 2003/03/03 20:22:42 das Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include "tclMacInt.h"
#include <Aliases.h>
#include <Errors.h>











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclMacChan.c
 *
 *	Channel drivers for Macintosh channels for the
 *	console fds.
 *
 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclMacChan.c,v 1.21.4.1 2004/02/07 05:48:02 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include "tclMacInt.h"
#include <Aliases.h>
#include <Errors.h>
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
	if (fd == 0) {
	    tsdPtr->stdinChannel = NULL;
	} else if (fd == 1) {
	    tsdPtr->stdoutChannel = NULL;
	} else if (fd == 2) {
	    tsdPtr->stderrChannel = NULL;
	} else {
	    panic("recieved invalid std file");
	}
    
	if (close(fd) < 0) {
	    errorCode = errno;
	}
    }
    return errorCode;







|







430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
	if (fd == 0) {
	    tsdPtr->stdinChannel = NULL;
	} else if (fd == 1) {
	    tsdPtr->stdoutChannel = NULL;
	} else if (fd == 2) {
	    tsdPtr->stderrChannel = NULL;
	} else {
	    Tcl_Panic("recieved invalid std file");
	}
    
	if (close(fd) < 0) {
	    errorCode = errno;
	}
    }
    return errorCode;
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
	    break;
	case TCL_STDERR:
	    fd = 2;
	    channelPermissions = TCL_WRITABLE;
	    bufMode = "none";
	    break;
	default:
	    panic("TclGetDefaultStdChannel: Unexpected channel type");
	    break;
    }

    sprintf(channelName, "console%d", (int) fd);
    fileState = (FileState *) ckalloc((unsigned) sizeof(FileState));
    channel = Tcl_CreateChannel(&consoleChannelType, channelName,
	    (ClientData) fileState, channelPermissions);







|







692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
	    break;
	case TCL_STDERR:
	    fd = 2;
	    channelPermissions = TCL_WRITABLE;
	    bufMode = "none";
	    break;
	default:
	    Tcl_Panic("TclGetDefaultStdChannel: Unexpected channel type");
	    break;
    }

    sprintf(channelName, "console%d", (int) fd);
    fileState = (FileState *) ckalloc((unsigned) sizeof(FileState));
    channel = Tcl_CreateChannel(&consoleChannelType, channelName,
	    (ClientData) fileState, channelPermissions);
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
    int errorCode = 0;
    OSErr err;

    err = FSClose(fileState->fileRef);
    FlushVol(NULL, fileState->volumeRef);
    if (err != noErr) {
	errorCode = errno = TclMacOSErrorToPosixError(err);
	panic("error during file close");
    }

    ckfree((char *) fileState);
    Tcl_SetErrno(errorCode);
    return errorCode;
}








|







983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
    int errorCode = 0;
    OSErr err;

    err = FSClose(fileState->fileRef);
    FlushVol(NULL, fileState->volumeRef);
    if (err != noErr) {
	errorCode = errno = TclMacOSErrorToPosixError(err);
	Tcl_Panic("error during file close");
    }

    ckfree((char *) fileState);
    Tcl_SetErrno(errorCode);
    return errorCode;
}

1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270

    /*
     * This could happen if the channel was created in one thread
     * and then moved to another without updating the thread
     * local data in each thread.
     */

    if (!removed)
        panic("file info ptr not on thread channel list");

}

/*
 *----------------------------------------------------------------------
 *
 * TclpSpliceFileChannel --
 *







|
|
|







1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270

    /*
     * This could happen if the channel was created in one thread
     * and then moved to another without updating the thread
     * local data in each thread.
     */

    if (!removed) {
        Tcl_Panic("file info ptr not on thread channel list");
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TclpSpliceFileChannel --
 *
Changes to mac/tclMacFile.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclMacFile.c --
 *
 *      This file implements the channel drivers for Macintosh
 *	files.  It also comtains Macintosh version of other Tcl
 *	functions that deal with the file system.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclMacFile.c,v 1.27.4.1 2003/10/16 02:28:03 dgp Exp $
 */

/*
 * Note: This code eventually needs to support async I/O.  In doing this
 * we will need to keep track of all current async I/O.  If exit to shell
 * is called - we shouldn't exit until all asyc I/O completes.
 */












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclMacFile.c --
 *
 *      This file implements the channel drivers for Macintosh
 *	files.  It also comtains Macintosh version of other Tcl
 *	functions that deal with the file system.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclMacFile.c,v 1.27.4.2 2004/02/07 05:48:02 dgp Exp $
 */

/*
 * Note: This code eventually needs to support async I/O.  In doing this
 * we will need to keep track of all current async I/O.  If exit to shell
 * is called - we shouldn't exit until all asyc I/O completes.
 */
151
152
153
154
155
156
157





158
159
160
161
162
163
164
    Tcl_GlobTypeData *types;	/* Object containing list of acceptable types.
				 * May be NULL. In particular the directory
				 * flag is very important. */
{
    OSType okType = 0;
    OSType okCreator = 0;
    Tcl_Obj *fileNamePtr;






    fileNamePtr = Tcl_FSGetTranslatedPath(interp, pathPtr);
    if (fileNamePtr == NULL) {
	return TCL_ERROR;
    }
    
    if (types != NULL) {







>
>
>
>
>







151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
    Tcl_GlobTypeData *types;	/* Object containing list of acceptable types.
				 * May be NULL. In particular the directory
				 * flag is very important. */
{
    OSType okType = 0;
    OSType okCreator = 0;
    Tcl_Obj *fileNamePtr;

    if (types != NULL && types->type == TCL_GLOB_TYPE_MOUNT) {
	/* The native filesystem never adds mounts */
	return TCL_OK;
    }

    fileNamePtr = Tcl_FSGetTranslatedPath(interp, pathPtr);
    if (fileNamePtr == NULL) {
	return TCL_ERROR;
    }
    
    if (types != NULL) {
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
	}
	return -1;
    }

    return 0;
}

/*


















 *----------------------------------------------------------------------

 *









































 * TclpObjGetCwd --
 *
 *	This function replaces the library version of getcwd().


 *
 * Results:
 *	The result is a pointer to a string specifying the current
 *	directory, or NULL if the current directory could not be
 *	determined.  If NULL is returned, an error message is left in the
 *	interp's result.  Storage for the result string is allocated in
 *	bufferPtr; the caller must call Tcl_DStringFree() when the result
 *	is no longer needed.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj* 
TclpObjGetCwd(interp)
    Tcl_Interp *interp;
{
    Tcl_DString ds;
    if (TclpGetCwd(interp, &ds) != NULL) {
	Tcl_Obj *cwdPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
	Tcl_IncrRefCount(cwdPtr);
	Tcl_DStringFree(&ds);
	return cwdPtr;
    } else {
	return NULL;
    }
}

CONST char *
TclpGetCwd(
    Tcl_Interp *interp,		/* If non-NULL, used for error reporting. */
    Tcl_DString *bufferPtr)	/* Uninitialized or free DString filled
				 * with name of current directory. */
{
    FSSpec theSpec;








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

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


>
>















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







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
	}
	return -1;
    }

    return 0;
}

/*
 *---------------------------------------------------------------------------
 *
 * TclpGetNativeCwd --
 *
 *	This function replaces the library version of getcwd().
 *
 * Results:
 *	The input and output are filesystem paths in native form.  The
 *	result is either the given clientData, if the working directory
 *	hasn't changed, or a new clientData (owned by our caller),
 *	giving the new native path, or NULL if the current directory
 *	could not be determined.  If NULL is returned, the caller can
 *	examine the standard posix error codes to determine the cause of
 *	the problem.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

ClientData
TclpGetNativeCwd(clientData)
    ClientData clientData;
{
    FSSpec theSpec;
    int length;
    Handle pathHandle = NULL;
    OSErr err;
    
    err = FSpGetDefaultDir(&theSpec);
    if (err != noErr) {
	errno = TclMacOSErrorToPosixError(err);
	return NULL;
    }
    err = FSpPathFromLocation(&theSpec, &length, &pathHandle);
    if (err != noErr) {
	errno = TclMacOSErrorToPosixError(err);
	return NULL;
    }
    
    if ((clientData != NULL) 
      && strcmp((CONST char*)(*pathHandle), (CONST char*)clientData) == 0) {
	/* No change to pwd */
	DisposeHandle(pathHandle);	
        return clientData;
    } else {
	char *newCd;
	
	HLock(pathHandle);
	newCd = (char *) ckalloc((unsigned) 
		(strlen((CONST char*)(*pathHandle)) + 1));
	strcpy(newCd, (CONST char*)(*pathHandle));
	HUnlock(pathHandle);
	DisposeHandle(pathHandle);
	return (ClientData) newCd;
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TclpGetCwd --
 *
 *	This function replaces the library version of getcwd().
 *      (Obsolete function, only retained for old extensions which
 *      may call it directly).
 *
 * Results:
 *	The result is a pointer to a string specifying the current
 *	directory, or NULL if the current directory could not be
 *	determined.  If NULL is returned, an error message is left in the
 *	interp's result.  Storage for the result string is allocated in
 *	bufferPtr; the caller must call Tcl_DStringFree() when the result
 *	is no longer needed.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */
















CONST char *
TclpGetCwd(
    Tcl_Interp *interp,		/* If non-NULL, used for error reporting. */
    Tcl_DString *bufferPtr)	/* Uninitialized or free DString filled
				 * with name of current directory. */
{
    FSSpec theSpec;
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj*
TclpFilesystemPathType(pathObjPtr)
    Tcl_Obj* pathObjPtr;
{
    /* All native paths are of the same type */
    return NULL;
}

/*
 *---------------------------------------------------------------------------







|
|







1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj*
TclpFilesystemPathType(pathPtr)
    Tcl_Obj* pathPtr;
{
    /* All native paths are of the same type */
    return NULL;
}

/*
 *---------------------------------------------------------------------------
Changes to mac/tclMacOSA.c.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 * Copyright (c) 1996 Lucent Technologies and Jim Ingham
 * Copyright (c) 1997 Sun Microsystems, Inc.
 *
 * See the file "License Terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclMacOSA.c,v 1.10 2002/10/09 11:54:30 das Exp $
 */

#define MAC_TCL

#include <Aliases.h>
#include <string.h>
#include <AppleEvents.h>







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 * Copyright (c) 1996 Lucent Technologies and Jim Ingham
 * Copyright (c) 1997 Sun Microsystems, Inc.
 *
 * See the file "License Terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclMacOSA.c,v 1.10.4.1 2004/02/07 05:48:02 dgp Exp $
 */

#define MAC_TCL

#include <Aliases.h>
#include <string.h>
#include <AppleEvents.h>
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
     * Registered At Startup...  If You Dynamically Load Components, This
     * Will Fail, But This Is Not A Common Thing To Do.
     */
	 
    LanguagesTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
	
    if (LanguagesTable == NULL) {
	panic("Memory Error Allocating Languages Hash Table");
    }
	
    Tcl_SetAssocData(interp, "OSAScript_LangTable", NULL, LanguagesTable);
    Tcl_InitHashTable(LanguagesTable, TCL_STRING_KEYS);
	
			
    while ((curComponent = FindNextComponent(curComponent, &compDescr)) != 0) {







|







218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
     * Registered At Startup...  If You Dynamically Load Components, This
     * Will Fail, But This Is Not A Common Thing To Do.
     */
	 
    LanguagesTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
	
    if (LanguagesTable == NULL) {
	Tcl_Panic("Memory Error Allocating Languages Hash Table");
    }
	
    Tcl_SetAssocData(interp, "OSAScript_LangTable", NULL, LanguagesTable);
    Tcl_InitHashTable(LanguagesTable, TCL_STRING_KEYS);
	
			
    while ((curComponent = FindNextComponent(curComponent, &compDescr)) != 0) {
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
    /*
     * Create the Component Assoc Data & put it in the interpreter.
     */
	
    ComponentTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
	
    if (ComponentTable == NULL) {
	panic("Memory Error Allocating Hash Table");
    }
	
    Tcl_SetAssocData(interp, "OSAScript_CompTable", NULL, ComponentTable);
			
    Tcl_InitHashTable(ComponentTable, TCL_STRING_KEYS);

    /*







|







296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
    /*
     * Create the Component Assoc Data & put it in the interpreter.
     */
	
    ComponentTable = (Tcl_HashTable *) ckalloc(sizeof(Tcl_HashTable));
	
    if (ComponentTable == NULL) {
	Tcl_Panic("Memory Error Allocating Hash Table");
    }
	
    Tcl_SetAssocData(interp, "OSAScript_CompTable", NULL, ComponentTable);
			
    Tcl_InitHashTable(ComponentTable, TCL_STRING_KEYS);

    /*
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
    CloseComponent(theComponent->theComponent);
	
    ComponentTable = (Tcl_HashTable *)
	Tcl_GetAssocData(theComponent->theInterp,
		"OSAScript_CompTable", (Tcl_InterpDeleteProc **) NULL);
	
    if (ComponentTable == NULL) {
	panic("Error, could not get the Component Table from the Associated data.");
    }
	
    hashEntry = Tcl_FindHashEntry(ComponentTable, theComponent->theName);
    if (hashEntry != NULL) {
	Tcl_DeleteHashEntry(hashEntry);
    }
    







|







1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
    CloseComponent(theComponent->theComponent);
	
    ComponentTable = (Tcl_HashTable *)
	Tcl_GetAssocData(theComponent->theInterp,
		"OSAScript_CompTable", (Tcl_InterpDeleteProc **) NULL);
	
    if (ComponentTable == NULL) {
	Tcl_Panic("Error, could not get the Component Table from the Associated data.");
    }
	
    hashEntry = Tcl_FindHashEntry(ComponentTable, theComponent->theName);
    if (hashEntry != NULL) {
	Tcl_DeleteHashEntry(hashEntry);
    }
    
Changes to mac/tclMacResource.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * tclMacResource.c --
 *
 *	This file contains several commands that manipulate or use
 *	Macintosh resources.  Included are extensions to the "source"
 *	command, the mac specific "beep" and "resource" commands, and
 *	administration for open resource file references.
 *
 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclMacResource.c,v 1.15.2.2 2003/10/16 02:28:03 dgp Exp $
 */

#include <Errors.h>
#include <FSpCompat.h>
#include <Processes.h>
#include <Resources.h>
#include <Sound.h>













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * tclMacResource.c --
 *
 *	This file contains several commands that manipulate or use
 *	Macintosh resources.  Included are extensions to the "source"
 *	command, the mac specific "beep" and "resource" commands, and
 *	administration for open resource file references.
 *
 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclMacResource.c,v 1.15.2.3 2004/02/07 05:48:02 dgp Exp $
 */

#include <Errors.h>
#include <FSpCompat.h>
#include <Processes.h>
#include <Resources.h>
#include <Sound.h>
474
475
476
477
478
479
480






481

482
483
484
485
486
487
488
		    if (theName[0] != 0) {
		        
			objPtr = Tcl_NewStringObj((char *) theName + 1,
				theName[0]);
		    } else {
			objPtr = Tcl_NewIntObj(id);
		    }






		    ReleaseResource(resource);

		    result = Tcl_ListObjAppendElement(interp, resultPtr,
			    objPtr);
		    if (result != TCL_OK) {
			Tcl_DecrRefCount(objPtr);
			break;
		    }
		}







>
>
>
>
>
>
|
>







474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
		    if (theName[0] != 0) {
		        
			objPtr = Tcl_NewStringObj((char *) theName + 1,
				theName[0]);
		    } else {
			objPtr = Tcl_NewIntObj(id);
		    }
		    /*
		     * If the Master Pointer of the  returned handle is
		     * null, then resource was not in memory, and it is
		     * safe to release it. Otherwise, it is not.
		     */
		    if (*resource == NULL) {
			ReleaseResource(resource);
		    }
		    result = Tcl_ListObjAppendElement(interp, resultPtr,
			    objPtr);
		    if (result != TCL_OK) {
			Tcl_DecrRefCount(objPtr);
			break;
		    }
		}
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
			macPermision = fsRdPerm;
		    break;
		    case O_WRONLY:
		    case O_RDWR:
			macPermision = fsRdWrShPerm;
			break;
		    default:
			panic("Tcl_ResourceObjCmd: invalid mode value");
		    break;
		}
	    } else {
		macPermision = fsRdPerm;
	    }
	    
	    /*







|







543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
			macPermision = fsRdPerm;
		    break;
		    case O_WRONLY:
		    case O_RDWR:
			macPermision = fsRdWrShPerm;
			break;
		    default:
			Tcl_Panic("Tcl_ResourceObjCmd: invalid mode value");
		    break;
		}
	    } else {
		macPermision = fsRdPerm;
	    }
	    
	    /*
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
	         * resource of this type & id, or the id was not specified.
	         */
	         
	        resource = NewHandle(length);
	        if (resource == NULL) {
	            resource = NewHandleSys(length);
	            if (resource == NULL) {
	                panic("could not allocate memory to write resource");
	            }
	        }
	        HLock(resource);
	        memcpy(*resource, stringPtr, length);
	        HUnlock(resource);
	        AddResource(resource, rezType, (short) rsrcId,
		    (StringPtr) resourceId);







|







787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
	         * resource of this type & id, or the id was not specified.
	         */
	         
	        resource = NewHandle(length);
	        if (resource == NULL) {
	            resource = NewHandleSys(length);
	            if (resource == NULL) {
	                Tcl_Panic("could not allocate memory to write resource");
	            }
	        }
	        HLock(resource);
	        memcpy(*resource, stringPtr, length);
	        HUnlock(resource);
	        AddResource(resource, rezType, (short) rsrcId,
		    (StringPtr) resourceId);
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
                                    " to overwrite it", (char *) NULL);
                            goto writeDone;
                    	}
                    }
                     
                    SetHandleSize(resource, length);
                    if ( MemError() != noErr ) {
                        panic("could not allocate memory to write resource");
                    }

                    HLock(resource);
	            memcpy(*resource, stringPtr, length);
	            HUnlock(resource);
	           
                    ChangedResource(resource);







|







858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
                                    " to overwrite it", (char *) NULL);
                            goto writeDone;
                    	}
                    }
                     
                    SetHandleSize(resource, length);
                    if ( MemError() != noErr ) {
                        Tcl_Panic("could not allocate memory to write resource");
                    }

                    HLock(resource);
	            memcpy(*resource, stringPtr, length);
	            HUnlock(resource);
	           
                    ChangedResource(resource);
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
	    
	    if (limitSearch) {
		UseResFile(saveRef);
	    }

	    return result;
	default:
	    panic("Tcl_GetIndexFromObj returned unrecognized option");
	    return TCL_ERROR;	/* Should never be reached. */
    }
}

/*
 *----------------------------------------------------------------------
 *







|







912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
	    
	    if (limitSearch) {
		UseResFile(saveRef);
	    }

	    return result;
	default:
	    Tcl_Panic("Tcl_GetIndexFromObj returned unrecognized option");
	    return TCL_ERROR;	/* Should never be reached. */
    }
}

/*
 *----------------------------------------------------------------------
 *
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
    }
    
    Tcl_SetHashValue(resourceHashPtr, resourceId);
    newId++;

    nameHashPtr = Tcl_CreateHashEntry(&nameTable, resourceId, &new);
    if (!new) {
	panic("resource id has repeated itself");
    }
    
    resourceRef = (OpenResourceFork *) ckalloc(sizeof(OpenResourceFork));
    resourceRef->fileRef = fileRef;
    resourceRef->flags = flags;
    
    Tcl_SetHashValue(nameHashPtr, (ClientData) resourceRef);







|







2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
    }
    
    Tcl_SetHashValue(resourceHashPtr, resourceId);
    newId++;

    nameHashPtr = Tcl_CreateHashEntry(&nameTable, resourceId, &new);
    if (!new) {
	Tcl_Panic("resource id has repeated itself");
    }
    
    resourceRef = (OpenResourceFork *) ckalloc(sizeof(OpenResourceFork));
    resourceRef->fileRef = fileRef;
    resourceRef->flags = flags;
    
    Tcl_SetHashValue(nameHashPtr, (ClientData) resourceRef);
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
	}
	if (match) {
	    index = i;
	    break;
	}
    }
    if (!match) {
        panic("the resource Fork List is out of synch!");
    }
    
    Tcl_ListObjReplace(NULL, resourceForkList, index, 1, 0, NULL);
    
    resourceHashPtr = Tcl_FindHashEntry(&resourceTable, (char *) fileRef);
    
    if (resourceHashPtr == NULL) {
	panic("Resource & Name tables are out of synch in resource command.");
    }
    ckfree(Tcl_GetHashValue(resourceHashPtr));
    Tcl_DeleteHashEntry(resourceHashPtr);
    
    return fileRef;

}







|







|







2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
	}
	if (match) {
	    index = i;
	    break;
	}
    }
    if (!match) {
	Tcl_Panic("the resource Fork List is out of synch!");
    }
    
    Tcl_ListObjReplace(NULL, resourceForkList, index, 1, 0, NULL);
    
    resourceHashPtr = Tcl_FindHashEntry(&resourceTable, (char *) fileRef);
    
    if (resourceHashPtr == NULL) {
	Tcl_Panic("Resource & Name tables are out of synch in resource command.");
    }
    ckfree(Tcl_GetHashValue(resourceHashPtr));
    Tcl_DeleteHashEntry(resourceHashPtr);
    
    return fileRef;

}
Changes to mac/tclMacSock.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 
 * tclMacSock.c
 *
 *	Channel drivers for Macintosh sockets.
 *
 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclMacSock.c,v 1.15 2003/04/22 23:20:43 andreas_kupries Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include "tclMacInt.h"
#include <AddressXlation.h>
#include <Aliases.h>










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 
 * tclMacSock.c
 *
 *	Channel drivers for Macintosh sockets.
 *
 * Copyright (c) 1996-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclMacSock.c,v 1.15.2.1 2004/02/07 05:48:02 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include "tclMacInt.h"
#include <AddressXlation.h>
#include <Aliases.h>
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
	closePB.csParam.close.ulpTimeoutValue = 60 /* seconds */;
	closePB.csParam.close.ulpTimeoutAction = 1 /* 1:abort 0:report */;
	closePB.csParam.close.validityFlags = timeoutValue | timeoutAction;
    	err = PBControlSync((ParmBlkPtr) &closePB);
    	if (err != noErr) {
    	    Debugger();
    	    goto afterRelease;
            /* panic("error closing server socket"); */
    	}
	statePtr->flags |= TCP_RELEASE;

	/*
	 * Server sockets are closed sync.  Therefor, we know it is OK to
	 * release the socket now.
	 */

	InitMacTCPParamBlock(&statePtr->pb, TCPRelease);
	statePtr->pb.tcpStream = statePtr->tcpStream;
	err = PBControlSync((ParmBlkPtr) &statePtr->pb);
	if (err != noErr) {
            panic("error releasing server socket");
	}

	/*
	 * Free the buffer space used by the socket and the 
	 * actual socket state data structure.
	 */
      afterRelease:







|












|







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
	closePB.csParam.close.ulpTimeoutValue = 60 /* seconds */;
	closePB.csParam.close.ulpTimeoutAction = 1 /* 1:abort 0:report */;
	closePB.csParam.close.validityFlags = timeoutValue | timeoutAction;
    	err = PBControlSync((ParmBlkPtr) &closePB);
    	if (err != noErr) {
    	    Debugger();
    	    goto afterRelease;
            /* Tcl_Panic("error closing server socket"); */
    	}
	statePtr->flags |= TCP_RELEASE;

	/*
	 * Server sockets are closed sync.  Therefor, we know it is OK to
	 * release the socket now.
	 */

	InitMacTCPParamBlock(&statePtr->pb, TCPRelease);
	statePtr->pb.tcpStream = statePtr->tcpStream;
	err = PBControlSync((ParmBlkPtr) &statePtr->pb);
	if (err != noErr) {
            Tcl_Panic("error releasing server socket");
	}

	/*
	 * Free the buffer space used by the socket and the 
	 * actual socket state data structure.
	 */
      afterRelease:
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
    /*
     * This could happen if the channel was created in one thread
     * and then moved to another without updating the thread
     * local data in each thread.
     */

    if (!removed)
        panic("file info ptr not on thread channel list");
    return;
}

/*
 *----------------------------------------------------------------------
 *
 * TclpSpliceSockChannel --







|







2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
    /*
     * This could happen if the channel was created in one thread
     * and then moved to another without updating the thread
     * local data in each thread.
     */

    if (!removed)
        Tcl_Panic("file info ptr not on thread channel list");
    return;
}

/*
 *----------------------------------------------------------------------
 *
 * TclpSpliceSockChannel --
Changes to mac/tclMacThrd.c.
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
     * has passed us a key without getting the value from 
     * TclpInitDataKey.
     */
     
    if ((int) keyVal <= 0)  {
        return NULL;
    } else if ((int) keyVal > keyCounter) {
        panic("illegal data key value");
    }
    
    GetCurrentThread(&curThread);
    
    for (dataPtr = tclMacDataKeyArray[(int) keyVal - 1]; dataPtr != NULL;
            dataPtr = dataPtr->next) {
        if (dataPtr->threadID ==  curThread) {







|







706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
     * has passed us a key without getting the value from 
     * TclpInitDataKey.
     */
     
    if ((int) keyVal <= 0)  {
        return NULL;
    } else if ((int) keyVal > keyCounter) {
        Tcl_Panic("illegal data key value");
    }
    
    GetCurrentThread(&curThread);
    
    for (dataPtr = tclMacDataKeyArray[(int) keyVal - 1]; dataPtr != NULL;
            dataPtr = dataPtr->next) {
        if (dataPtr->threadID ==  curThread) {
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
    ThreadID curThread;
    TclMacThrdData *dataPtr, *prevPtr;
    
     
    if ((int) keyVal <= 0)  {
        return NULL;
    } else if ((int) keyVal > keyCounter) {
        panic("illegal data key value");
    }
    
    GetCurrentThread(&curThread);
    
    for (dataPtr = tclMacDataKeyArray[(int) keyVal - 1], prevPtr = NULL; 
            dataPtr != NULL;
            prevPtr = dataPtr, dataPtr = dataPtr->next) {







|







751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
    ThreadID curThread;
    TclMacThrdData *dataPtr, *prevPtr;
    
     
    if ((int) keyVal <= 0)  {
        return NULL;
    } else if ((int) keyVal > keyCounter) {
        Tcl_Panic("illegal data key value");
    }
    
    GetCurrentThread(&curThread);
    
    for (dataPtr = tclMacDataKeyArray[(int) keyVal - 1], prevPtr = NULL; 
            dataPtr != NULL;
            prevPtr = dataPtr, dataPtr = dataPtr->next) {
Changes to macosx/Makefile.
1
2
3
4
5
6
7
8
9
10
11
12
13
########################################################################################################
#
# Makefile to build Tcl on Mac OS X packaged as a Framework
#	uses standard unix build system in tcl/unix
#
# RCS: @(#) $Id: Makefile,v 1.5.4.2 2003/10/16 02:28:03 dgp Exp $
#
########################################################################################################

#-------------------------------------------------------------------------------------------------------
# customizable settings

DESTDIR			?=





|







1
2
3
4
5
6
7
8
9
10
11
12
13
########################################################################################################
#
# Makefile to build Tcl on Mac OS X packaged as a Framework
#	uses standard unix build system in tcl/unix
#
# RCS: @(#) $Id: Makefile,v 1.5.4.3 2004/02/07 05:48:02 dgp Exp $
#
########################################################################################################

#-------------------------------------------------------------------------------------------------------
# customizable settings

DESTDIR			?=
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
TCL_PACKAGE_PATH	?= "~/Library/Tcl /Library/Tcl /Network/Library/Tcl /System/Library/Tcl \
			    ~/Library/Frameworks /Library/Frameworks /Network/Library/Frameworks \
			    /System/Library/Frameworks"

#-------------------------------------------------------------------------------------------------------
# meta targets

meta 			:= all install embedded install-embedded clean distclean

styles			:= develop deploy

all			:= ${styles}
all			: ${all}

install			:= ${styles:%=install-%}







|







31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
TCL_PACKAGE_PATH	?= "~/Library/Tcl /Library/Tcl /Network/Library/Tcl /System/Library/Tcl \
			    ~/Library/Frameworks /Library/Frameworks /Network/Library/Frameworks \
			    /System/Library/Frameworks"

#-------------------------------------------------------------------------------------------------------
# meta targets

meta 			:= all install embedded install-embedded clean distclean test

styles			:= develop deploy

all			:= ${styles}
all			: ${all}

install			:= ${styles:%=install-%}
53
54
55
56
57
58
59




60
61
62
63
64
65
66
67
68
69

70
71
72
73
74
75
76

clean			:= ${styles:%=clean-%}
clean			: ${clean}
clean-%:		action := clean-
distclean		:= ${styles:%=distclean-%}
distclean		: ${distclean}
distclean-%:		action := distclean-





targets			:= $(foreach v,${meta},${$v})

#-------------------------------------------------------------------------------------------------------
# build styles

develop_make_args	:= BUILD_STYLE=Development CONFIGURE_ARGS=--enable-symbols
deploy_make_args	:= BUILD_STYLE=Deployment \
			   MAKE_ARGS=INSTALL_PROGRAM="'$$\$${INSTALL} $$\$${INSTALL_STRIP_PROGRAM}'" \
			   MAKE_ARGS+=INSTALL_LIBRARY="'$$\$${INSTALL} $$\$${INSTALL_STRIP_LIBRARY}'"

embedded_make_args	:= EMBEDDED_BUILD=1
install_make_args	:= INSTALL_BUILD=1

$(targets): 
	${MAKE} ${action}${PROJECT} \
	$(foreach s,${styles} embedded install,$(if $(findstring $s,$@),${${s}_make_args}))








>
>
>
>









|
>







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

clean			:= ${styles:%=clean-%}
clean			: ${clean}
clean-%:		action := clean-
distclean		:= ${styles:%=distclean-%}
distclean		: ${distclean}
distclean-%:		action := distclean-

test			:= ${styles:%=test-%}
test			: ${test}
test-%:			action := test-

targets			:= $(foreach v,${meta},${$v})

#-------------------------------------------------------------------------------------------------------
# build styles

develop_make_args	:= BUILD_STYLE=Development CONFIGURE_ARGS=--enable-symbols
deploy_make_args	:= BUILD_STYLE=Deployment \
			   MAKE_ARGS=INSTALL_PROGRAM="'$$\$${INSTALL} $$\$${INSTALL_STRIP_PROGRAM}'" \
			   MAKE_ARGS+=INSTALL_LIBRARY="'$$\$${INSTALL} $$\$${INSTALL_STRIP_LIBRARY}'" \
			   MAKE_ARGS+=MEM_DEBUG_FLAGS="-DNDEBUG"
embedded_make_args	:= EMBEDDED_BUILD=1
install_make_args	:= INSTALL_BUILD=1

$(targets): 
	${MAKE} ${action}${PROJECT} \
	$(foreach s,${styles} embedded install,$(if $(findstring $s,$@),${${s}_make_args}))

139
140
141
142
143
144
145



146
147
148
149
150
151
152
clean-${PROJECT}:
	${MAKE} -C ${OBJ_DIR} clean ${EXTRA_MAKE_ARGS}

distclean-${PROJECT}:
	${MAKE} -C ${OBJ_DIR} distclean ${EXTRA_MAKE_ARGS}
	rm -rf ${OBJ_DIR} ${PRODUCT_NAME}.framework tclsh${PRODUCT_VERSION} tcltest
	



install-${PROJECT}: build-${PROJECT}
# install to ${INSTALL_ROOT} with optional stripping
	${MAKE} -C ${OBJ_DIR} install-binaries install-libraries \
	SCRIPT_INSTALL_DIR=${INSTALL_ROOT}${SCRIPTDIR} ${MAKE_ARGS_V} ${MAKE_ARGS} ${EXTRA_MAKE_ARGS}
	mkdir -p ${INSTALL_ROOT}${PRIVATEINCLUDEDIR} && \
	cd ${GENERIC_DIR} && ${CPPROG} ${PRIVATE_HEADERS} ${INSTALL_ROOT}${PRIVATEINCLUDEDIR}
ifeq (${BUILD_STYLE},Development)







>
>
>







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
clean-${PROJECT}:
	${MAKE} -C ${OBJ_DIR} clean ${EXTRA_MAKE_ARGS}

distclean-${PROJECT}:
	${MAKE} -C ${OBJ_DIR} distclean ${EXTRA_MAKE_ARGS}
	rm -rf ${OBJ_DIR} ${PRODUCT_NAME}.framework tclsh${PRODUCT_VERSION} tcltest
	
test-${PROJECT}: build-${PROJECT}
	${MAKE} -C ${OBJ_DIR} test ${EXTRA_MAKE_ARGS}

install-${PROJECT}: build-${PROJECT}
# install to ${INSTALL_ROOT} with optional stripping
	${MAKE} -C ${OBJ_DIR} install-binaries install-libraries \
	SCRIPT_INSTALL_DIR=${INSTALL_ROOT}${SCRIPTDIR} ${MAKE_ARGS_V} ${MAKE_ARGS} ${EXTRA_MAKE_ARGS}
	mkdir -p ${INSTALL_ROOT}${PRIVATEINCLUDEDIR} && \
	cd ${GENERIC_DIR} && ${CPPROG} ${PRIVATE_HEADERS} ${INSTALL_ROOT}${PRIVATEINCLUDEDIR}
ifeq (${BUILD_STYLE},Development)
Changes to tests/async.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
# Commands covered:  none
#
# This file contains a collection of tests for Tcl_AsyncCreate and related
# library procedures.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1993 The Regents of the University of California.
# Copyright (c) 1994-1996 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.
#
# RCS: @(#) $Id: async.test,v 1.5.26.1 2003/08/07 21:36:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

if {[info commands testasync] == {}} {
    puts "This application hasn't been compiled with the \"testasync\""
    puts "command, so I can't test Tcl_AsyncCreate et al."
    ::tcltest::cleanupTests
    return
}





proc async1 {result code} {
    global aresult acode
    set aresult $result
    set acode $code
    return "new result"
}













|












>
>
>
>







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
# Commands covered:  none
#
# This file contains a collection of tests for Tcl_AsyncCreate and related
# library procedures.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1993 The Regents of the University of California.
# Copyright (c) 1994-1996 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.
#
# RCS: @(#) $Id: async.test,v 1.5.26.2 2004/02/07 05:48:02 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

if {[info commands testasync] == {}} {
    puts "This application hasn't been compiled with the \"testasync\""
    puts "command, so I can't test Tcl_AsyncCreate et al."
    ::tcltest::cleanupTests
    return
}

tcltest::testConstraint threaded [expr {
    [info exists ::tcl_platform(threaded)] && $::tcl_platform(threaded)
}]

proc async1 {result code} {
    global aresult acode
    set aresult $result
    set acode $code
    return "new result"
}
141
142
143
144
145
146
147
148

149




150
151
152
153
154
155
156

157








158








159








160








161








162
163




164



set hm3 [testasync create mult2]
set hm4 [testasync create del2]

test async-3.1 {deleting handlers} {
    set x {}
    list [catch {testasync mark $hm2 "foobar" 5} msg] $msg $x
} {3 del2 {0 0 0 del1 del2}}


# cleanup




testasync delete
::tcltest::cleanupTests
return




































































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

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

>
>
>
>

>
>
>
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
set hm3 [testasync create mult2]
set hm4 [testasync create del2]

test async-3.1 {deleting handlers} {
    set x {}
    list [catch {testasync mark $hm2 "foobar" 5} msg] $msg $x
} {3 del2 {0 0 0 del1 del2}}

proc nothing {} {
    # empty proc
}
proc hang1 {handle} {
    global aresult
    set aresult {Async event not delivered}
    testasync marklater $handle

    for {set i 0} {
	$i < 2500000  &&  $aresult eq "Async event not delivered"
    } {incr i} {
	nothing
    }
    return $aresult
}
proc hang2 {handle} {
    global aresult
    set aresult {Async event not delivered}
    testasync marklater $handle
    for {set i 0} {
	$i < 2500000  &&  $aresult eq "Async event not delivered"
    } {incr i} {}
    return $aresult
}
proc hang3 {handle} [concat {
    global aresult
    set aresult {Async event not delivered}
    testasync marklater $handle
    set i 0
} [string repeat {;incr i;} 1500000] {
    return $aresult
}]

test async-4.1 {async interrupting bytecode sequence} -constraints {
    threaded
} -setup {
    set hm [testasync create async3]
} -body {
    hang1 $hm
} -result {test pattern} -cleanup {
    testasync delete $hm
}
test async-4.2 {async interrupting straight bytecode sequence} -constraints {
    threaded
} -setup {
    set hm [testasync create async3]
} -body {
    hang2 $hm
} -result {test pattern} -cleanup {
    testasync delete $hm
}
test async-4.3 {async interrupting loop-less bytecode sequence} -constraints {
    threaded
} -setup {
    set hm [testasync create async3]
} -body {
    hang3 $hm
} -result {test pattern} -cleanup {
    testasync delete $hm
}

# cleanup
testasync delete
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:
Changes to tests/basic.test.
11
12
13
14
15
16
17
18
19
20
21
22
23

24
25
26
27
28
29
30
#
# 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.
#
# RCS: @(#) $Id: basic.test,v 1.27.2.2 2003/08/07 21:36:04 dgp Exp $
#

package require tcltest 2
namespace import -force ::tcltest::*


testConstraint testcmdtoken [llength [info commands testcmdtoken]]
testConstraint testcreatecommand [llength [info commands testcreatecommand]]
testConstraint exec [llength [info commands exec]]

catch {namespace delete test_ns_basic}
catch {interp delete test_interp}
catch {rename p ""}







|





>







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#
# 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.
#
# RCS: @(#) $Id: basic.test,v 1.27.2.3 2004/02/07 05:48:02 dgp Exp $
#

package require tcltest 2
namespace import -force ::tcltest::*

testConstraint testevalex [llength [info commands testevalex]]
testConstraint testcmdtoken [llength [info commands testcmdtoken]]
testConstraint testcreatecommand [llength [info commands testcreatecommand]]
testConstraint exec [llength [info commands exec]]

catch {namespace delete test_ns_basic}
catch {interp delete test_interp}
catch {rename p ""}
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
         [cmd] \
         [rename cmd ""] \
         [interp expose {} cmd] \
         [p]
} {42 {} {} Hello {} {} 42}

test basic-14.1 {Tcl_CreateCommand, new cmd goes into a namespace specified in its name, if any} {testcreatecommand} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [testcreatecommand create] \
	 [test_ns_basic::createdcommand] \
	 [testcreatecommand delete]
} {{} {CreatedCommandProc in ::test_ns_basic} {}}
test basic-14.2 {Tcl_CreateCommand, namespace code ignore single ":"s in middle or end of names} {testcreatecommand} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {rename value:at: ""}
    list [testcreatecommand create2] \
	 [value:at:] \
	 [testcreatecommand delete2]
} {{} {CreatedCommandProc2 in ::} {}}

test basic-15.1 {Tcl_CreateObjCommand, new cmd goes into a namespace specified in its name, if any} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_basic {}
    proc test_ns_basic::cmd {} {  ;# proc requires that ns already exist
        return [namespace current]
    }
    list [test_ns_basic::cmd] \
         [namespace delete test_ns_basic]
} {::test_ns_basic {}}

test basic-16.1 {TclInvokeStringCommand} {emptyTest} {
} {}

test basic-17.1 {TclInvokeObjCommand} {emptyTest} {
} {}

test basic-18.1 {TclRenameCommand, name of existing cmd can have namespace qualifiers} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {rename cmd ""}
    namespace eval test_ns_basic {
        proc p {} {
            return "p in [namespace current]"
        }
    }
    list [test_ns_basic::p] \
         [rename test_ns_basic::p test_ns_basic::q] \
         [test_ns_basic::q] 
} {{p in ::test_ns_basic} {} {p in ::test_ns_basic}}
test basic-18.2 {TclRenameCommand, existing cmd must be found} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [catch {rename test_ns_basic::p test_ns_basic::q} msg] $msg
} {1 {can't rename "test_ns_basic::p": command doesn't exist}}
test basic-18.3 {TclRenameCommand, delete cmd if new name is empty} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_basic {
        proc p {} {
            return "p in [namespace current]"
        }
    }
    list [info commands test_ns_basic::*] \
         [rename test_ns_basic::p ""] \
         [info commands test_ns_basic::*]
} {::test_ns_basic::p {} {}}
test basic-18.4 {TclRenameCommand, bad new name} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_basic {
        proc p {} {
            return "p in [namespace current]"
        }
    }
    rename test_ns_basic::p :::george::martha
} {}
test basic-18.5 {TclRenameCommand, new name must not already exist} {
    namespace eval test_ns_basic {
        proc q {} {
            return 42
        }
    }
    list [catch {rename test_ns_basic::q :::george::martha} msg] $msg
} {1 {can't rename to ":::george::martha": command already exists}}
test basic-18.6 {TclRenameCommand, check for command shadowing by newly renamed cmd} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {rename p ""}
    catch {rename q ""}
    proc p {} {
        return "p in [namespace current]"
    }
    proc q {} {
        return "q in [namespace current]"







|





|







|















|











|



|










|
















|







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
         [cmd] \
         [rename cmd ""] \
         [interp expose {} cmd] \
         [p]
} {42 {} {} Hello {} {} 42}

test basic-14.1 {Tcl_CreateCommand, new cmd goes into a namespace specified in its name, if any} {testcreatecommand} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [testcreatecommand create] \
	 [test_ns_basic::createdcommand] \
	 [testcreatecommand delete]
} {{} {CreatedCommandProc in ::test_ns_basic} {}}
test basic-14.2 {Tcl_CreateCommand, namespace code ignore single ":"s in middle or end of names} {testcreatecommand} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {rename value:at: ""}
    list [testcreatecommand create2] \
	 [value:at:] \
	 [testcreatecommand delete2]
} {{} {CreatedCommandProc2 in ::} {}}

test basic-15.1 {Tcl_CreateObjCommand, new cmd goes into a namespace specified in its name, if any} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_basic {}
    proc test_ns_basic::cmd {} {  ;# proc requires that ns already exist
        return [namespace current]
    }
    list [test_ns_basic::cmd] \
         [namespace delete test_ns_basic]
} {::test_ns_basic {}}

test basic-16.1 {TclInvokeStringCommand} {emptyTest} {
} {}

test basic-17.1 {TclInvokeObjCommand} {emptyTest} {
} {}

test basic-18.1 {TclRenameCommand, name of existing cmd can have namespace qualifiers} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {rename cmd ""}
    namespace eval test_ns_basic {
        proc p {} {
            return "p in [namespace current]"
        }
    }
    list [test_ns_basic::p] \
         [rename test_ns_basic::p test_ns_basic::q] \
         [test_ns_basic::q] 
} {{p in ::test_ns_basic} {} {p in ::test_ns_basic}}
test basic-18.2 {TclRenameCommand, existing cmd must be found} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [catch {rename test_ns_basic::p test_ns_basic::q} msg] $msg
} {1 {can't rename "test_ns_basic::p": command doesn't exist}}
test basic-18.3 {TclRenameCommand, delete cmd if new name is empty} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_basic {
        proc p {} {
            return "p in [namespace current]"
        }
    }
    list [info commands test_ns_basic::*] \
         [rename test_ns_basic::p ""] \
         [info commands test_ns_basic::*]
} {::test_ns_basic::p {} {}}
test basic-18.4 {TclRenameCommand, bad new name} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_basic {
        proc p {} {
            return "p in [namespace current]"
        }
    }
    rename test_ns_basic::p :::george::martha
} {}
test basic-18.5 {TclRenameCommand, new name must not already exist} {
    namespace eval test_ns_basic {
        proc q {} {
            return 42
        }
    }
    list [catch {rename test_ns_basic::q :::george::martha} msg] $msg
} {1 {can't rename to ":::george::martha": command already exists}}
test basic-18.6 {TclRenameCommand, check for command shadowing by newly renamed cmd} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {rename p ""}
    catch {rename q ""}
    proc p {} {
        return "p in [namespace current]"
    }
    proc q {} {
        return "q in [namespace current]"
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
         [test_ns_basic::callP]
} {{p in ::} {} {q in ::test_ns_basic}}

test basic-19.1 {Tcl_SetCommandInfo} {emptyTest} {
} {}

test basic-20.1 {Tcl_GetCommandInfo, names for commands created inside namespaces} {testcmdtoken} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {rename p ""}
    catch {rename q ""}
    catch {unset x}
    set x [namespace eval test_ns_basic::test_ns_basic2 {
        # the following creates a cmd in the global namespace
        testcmdtoken create p
    }]
    list [testcmdtoken name $x] \
         [rename ::p q] \
         [testcmdtoken name $x]
} {{p ::p} {} {q ::q}}
test basic-20.2 {Tcl_GetCommandInfo, names for commands created outside namespaces} {testcmdtoken} {
    catch {rename q ""}
    set x [testcmdtoken create test_ns_basic::test_ns_basic2::p]
    list [testcmdtoken name $x] \
         [rename test_ns_basic::test_ns_basic2::p q] \
         [testcmdtoken name $x]
} {{p ::test_ns_basic::test_ns_basic2::p} {} {q ::q}}
test basic-20.3 {Tcl_GetCommandInfo, #-quoting} {
    catch {rename \# ""}
    set x [testcmdtoken create \#]
    testcmdtoken name $x
} {{#} ::#}

test basic-21.1 {Tcl_GetCommandName} {emptyTest} {
} {}

test basic-22.1 {Tcl_GetCommandFullName} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_basic1 {
        namespace export cmd*
        proc cmd1 {} {}
        proc cmd2 {} {}
    }
    namespace eval test_ns_basic2 {
        namespace export *







|


















|









|







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
         [test_ns_basic::callP]
} {{p in ::} {} {q in ::test_ns_basic}}

test basic-19.1 {Tcl_SetCommandInfo} {emptyTest} {
} {}

test basic-20.1 {Tcl_GetCommandInfo, names for commands created inside namespaces} {testcmdtoken} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {rename p ""}
    catch {rename q ""}
    catch {unset x}
    set x [namespace eval test_ns_basic::test_ns_basic2 {
        # the following creates a cmd in the global namespace
        testcmdtoken create p
    }]
    list [testcmdtoken name $x] \
         [rename ::p q] \
         [testcmdtoken name $x]
} {{p ::p} {} {q ::q}}
test basic-20.2 {Tcl_GetCommandInfo, names for commands created outside namespaces} {testcmdtoken} {
    catch {rename q ""}
    set x [testcmdtoken create test_ns_basic::test_ns_basic2::p]
    list [testcmdtoken name $x] \
         [rename test_ns_basic::test_ns_basic2::p q] \
         [testcmdtoken name $x]
} {{p ::test_ns_basic::test_ns_basic2::p} {} {q ::q}}
test basic-20.3 {Tcl_GetCommandInfo, #-quoting} testcmdtoken {
    catch {rename \# ""}
    set x [testcmdtoken create \#]
    testcmdtoken name $x
} {{#} ::#}

test basic-21.1 {Tcl_GetCommandName} {emptyTest} {
} {}

test basic-22.1 {Tcl_GetCommandFullName} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_basic1 {
        namespace export cmd*
        proc cmd1 {} {}
        proc cmd2 {} {}
    }
    namespace eval test_ns_basic2 {
        namespace export *
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
        }
    }
    list $x \
         [interp eval test_interp {useSet}] \
         [interp delete test_interp]
} {123 {set called with a 123} {}}
test basic-24.2 {Tcl_DeleteCommandFromToken, deleting commands changes command epoch} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {rename p ""}
    proc p {} {
        return "global p"
    }
    namespace eval test_ns_basic {
        proc p {} {
            return "namespace p"
        }
        proc callP {} {
            p
        }
    }
    list [test_ns_basic::callP] \
         [rename test_ns_basic::p ""] \
         [test_ns_basic::callP]
} {{namespace p} {} {global p}}
test basic-24.3 {Tcl_DeleteCommandFromToken, delete imported cmds that refer to a deleted cmd} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {rename p ""}
    namespace eval test_ns_basic {
        namespace export p
        proc p {} {return 42}
    }
    namespace eval test_ns_basic2 {
        namespace import ::test_ns_basic::*







|

















|







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
        }
    }
    list $x \
         [interp eval test_interp {useSet}] \
         [interp delete test_interp]
} {123 {set called with a 123} {}}
test basic-24.2 {Tcl_DeleteCommandFromToken, deleting commands changes command epoch} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {rename p ""}
    proc p {} {
        return "global p"
    }
    namespace eval test_ns_basic {
        proc p {} {
            return "namespace p"
        }
        proc callP {} {
            p
        }
    }
    list [test_ns_basic::callP] \
         [rename test_ns_basic::p ""] \
         [test_ns_basic::callP]
} {{namespace p} {} {global p}}
test basic-24.3 {Tcl_DeleteCommandFromToken, delete imported cmds that refer to a deleted cmd} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {rename p ""}
    namespace eval test_ns_basic {
        namespace export p
        proc p {} {return 42}
    }
    namespace eval test_ns_basic2 {
        namespace import ::test_ns_basic::*
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
test basic-34.1 {TclGlobalInvoke} {emptyTest} {
} {}

test basic-35.1 {TclObjInvokeGlobal} {emptyTest} {
} {}

test basic-36.1 {TclObjInvoke, lookup of "unknown" command} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {interp delete test_interp}
    interp create test_interp
    interp eval test_interp {
        proc unknown {args} {
            return "global unknown"
        }
        namespace eval test_ns_basic {







|







456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
test basic-34.1 {TclGlobalInvoke} {emptyTest} {
} {}

test basic-35.1 {TclObjInvokeGlobal} {emptyTest} {
} {}

test basic-36.1 {TclObjInvoke, lookup of "unknown" command} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {interp delete test_interp}
    interp create test_interp
    interp eval test_interp {
        proc unknown {args} {
            return "global unknown"
        }
        namespace eval test_ns_basic {
583
584
585
586
587
588
589





590













































































































































































































































































































591
592
593
594
595
596
597
598
599
600
601
"return -code return"
    (file "BREAKtest" line 2)}}

test basic-47.1 {Tcl_EvalEx: check for missing close-bracket} -body {
    subst {a[set b [format cd]}
} -returnCodes error -result {missing close-bracket}




















































































































































































































































































































# cleanup
catch {eval namespace delete [namespace children :: test_ns_*]}
catch {namespace delete george}
catch {interp delete test_interp}
catch {rename p ""}
catch {rename q ""}
catch {rename cmd ""}
catch {rename value:at: ""}
catch {unset x}
::tcltest::cleanupTests
return







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









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
"return -code return"
    (file "BREAKtest" line 2)}}

test basic-47.1 {Tcl_EvalEx: check for missing close-bracket} -body {
    subst {a[set b [format cd]}
} -returnCodes error -result {missing close-bracket}

# Some lists for expansion tests to work with
set l1 [list a {b b} c d]
set l2 [list e f {g g} h]
proc l3 {} {
    list i j k {l l}
}

# Do all tests once byte compiled and once with direct string evaluation
for {set noComp 0} {$noComp <= 1} {incr noComp} {

if $noComp {
    interp alias {} run {} testevalex
    set constraints testevalex
} else {
    interp alias {} run {} if 1
    set constraints {}
}

test basic-47.2.$noComp {Tcl_EvalEx: error during word expansion} -body {
    run {{expand}\{}
} -constraints $constraints -returnCodes error -result {unmatched open brace in list}

test basic-47.3.$noComp {Tcl_EvalEx, error during substitution} -body {
    run {{expand}[error foo]}
} -constraints $constraints -returnCodes error -result foo

test basic-47.4.$noComp {Tcl_EvalEx: no expansion} $constraints {
    run {list {expand} {expand}	{expand}}
} {expand expand expand}

test basic-47.5.$noComp {Tcl_EvalEx: expansion} $constraints {
    run {list {expand}{} {expand}	{expand}x {expand}"y z"}
} {expand x y z}

test basic-47.6.$noComp {Tcl_EvalEx: expansion to zero args} $constraints {
    run {list {expand}{}}
} {}

test basic-47.7.$noComp {Tcl_EvalEx: expansion to one arg} $constraints {
    run {list {expand}x}
} x

test basic-47.8.$noComp {Tcl_EvalEx: expansion to many args} $constraints {
    run {list {expand}"y z"}
} {y z}

test basic-47.9.$noComp {Tcl_EvalEx: expansion and subst order} $constraints {
    set x 0
    run {list [incr x] {expand}[incr x] [incr x] \
		{expand}[list [incr x] [incr x]] [incr x]}
} {1 2 3 4 5 6}

test basic-47.10.$noComp {Tcl_EvalEx: expand and memory management} $constraints {
    run {concat {expand}{} a b c d e f g h i j k l m n o p q r}
} {a b c d e f g h i j k l m n o p q r}

test basic-47.11.$noComp {Tcl_EvalEx: expand and memory management} $constraints {
    run {concat {expand}1 a b c d e f g h i j k l m n o p q r}
} {1 a b c d e f g h i j k l m n o p q r}

test basic-47.12.$noComp {Tcl_EvalEx: expand and memory management} $constraints {
    run {concat {expand}{1 2} a b c d e f g h i j k l m n o p q r}
} {1 2 a b c d e f g h i j k l m n o p q r}

test basic-47.13.$noComp {Tcl_EvalEx: expand and memory management} $constraints {
    run {concat {expand}{} {expand}{1 2} a b c d e f g h i j k l m n o p q}
} {1 2 a b c d e f g h i j k l m n o p q}

test basic-47.14.$noComp {Tcl_EvalEx: expand and memory management} $constraints {
    run {concat {expand}{} a b c d e f g h i j k l m n o p q r s}
} {a b c d e f g h i j k l m n o p q r s}

test basic-47.15.$noComp {Tcl_EvalEx: expand and memory management} $constraints {
    run {concat {expand}1 a b c d e f g h i j k l m n o p q r s}
} {1 a b c d e f g h i j k l m n o p q r s}

test basic-47.16.$noComp {Tcl_EvalEx: expand and memory management} $constraints {
    run {concat {expand}{1 2} a b c d e f g h i j k l m n o p q r s}
} {1 2 a b c d e f g h i j k l m n o p q r s}

test basic-47.17.$noComp {Tcl_EvalEx: expand and memory management} $constraints {
    run {concat {expand}{} {expand}{1 2} a b c d e f g h i j k l m n o p q r}
} {1 2 a b c d e f g h i j k l m n o p q r}

test basic-48.1.$noComp {expansion: parsing} $constraints {
	run { # A comment

		# Another comment
		list 1  2\
			3   {expand}$::l1
            
		# Comment again
	}
} {1 2 3 a {b b} c d}

test basic-48.2.$noComp {no expansion} $constraints {
        run {list $::l1 $::l2 [l3]}
} {{a {b b} c d} {e f {g g} h} {i j k {l l}}}

test basic-48.3.$noComp {expansion} $constraints {
        run {list {expand}$::l1 $::l2 {expand}[l3]}
} {a {b b} c d {e f {g g} h} i j k {l l}}

test basic-48.4.$noComp {expansion: really long cmd} $constraints {
        set cmd [list list]
        for {set t 0} {$t < 500} {incr t} {
            lappend cmd {{expand}$::l1}
        }
        llength [run [join $cmd]]
} 2000

test basic-48.5.$noComp {expansion: error detection} -setup {
	set l "a {a b}x y"
} -constraints $constraints -body {
	run {list $::l1 {expand}$l}
} -cleanup {
	unset l
} -returnCodes 1 -result {list element in braces followed by "x" instead of space}

test basic-48.6.$noComp {expansion: odd usage} $constraints {
        run {list {expand}$::l1$::l2}
} {a {b b} c de f {g g} h}

test basic-48.7.$noComp {expansion: odd usage} -constraints $constraints -body {
        run {list {expand}[l3]$::l1}
} -returnCodes 1 -result {list element in braces followed by "a" instead of space}

test basic-48.8.$noComp {expansion: odd usage} $constraints {
        run {list {expand}hej$::l1}
} {heja {b b} c d}

test basic-48.9.$noComp {expansion: Not all {expand} should trigger} $constraints {
	run {list {expand}$::l1 \{expand\}$::l2 "{expand}$::l1" {{expand} i j k}}
} {a {b b} c d {{expand}e f {g g} h} {{expand}a {b b} c d} {{expand} i j k}}

test basic-48.10.$noComp {expansion: expansion of command word} -setup {
	set cmd [list string range jultomte]
} -constraints $constraints -body {
	run {{expand}$cmd 2 6}
} -cleanup {
	unset cmd
} -result ltomt

test basic-48.11.$noComp {expansion: expansion into nothing} -setup {
        set cmd {}
        set bar {}
} -constraints $constraints -body {
        run {{expand}$cmd {expand}$bar}
} -cleanup {
	unset cmd bar
} -result {}

test basic-48.12.$noComp {expansion: odd usage} $constraints {
	run {list {expand}$::l1 {expand}"hej hopp" {expand}$::l2}
} {a {b b} c d hej hopp e f {g g} h}

test basic-48.13.$noComp {expansion: odd usage} $constraints {
	run {list {expand}$::l1 {expand}{hej hopp} {expand}$::l2}
} {a {b b} c d hej hopp e f {g g} h}

test basic-48.14.$noComp {expansion: hash command} -setup {
        catch {rename \# ""}
        set cmd "#"
    } -constraints $constraints -body { 
           run { {expand}$cmd apa bepa }
    } -cleanup {
	unset cmd
} -returnCodes 1 -result {invalid command name "#"}

test basic-48.15.$noComp {expansion: complex words} -setup {
            set a(x) [list a {b c} d e]
            set b x
            set c [list {f\ g h\ i j k} x y]
            set d {0\ 1 2 3}
    } -constraints $constraints -body {
            run { lappend d {expand}$a($b) {expand}[lindex $c 0] }
    } -cleanup {
	unset a b c d
} -result {{0 1} 2 3 a {b c} d e {f g} {h i} j k}

testConstraint memory [llength [info commands memory]]
test basic-48.16.$noComp {expansion: testing for leaks} -setup {
        proc getbytes {} {
            set lines [split [memory info] "\n"]
            lindex [lindex $lines 3] 3
        }
        # This test is made to stress the allocation, reallocation and
        # object reference management in Tcl_EvalEx.
        proc stress {} {
            set a x
            # Create free objects that should disappear
            set l [list 1$a 2$a 3$a 4$a 5$a 6$a 7$a]
            # A short number of words and a short result (8)
            set l [run {list {expand}$l $a$a}]
            # A short number of words and a longer result (27)
            set l [run {list {expand}$l $a$a {expand}$l $a$a {expand}$l $a$a}]
            # A short number of words and a longer result, with an error
            # This is to stress the cleanup in the error case
            if {![catch {run {_moo_ {expand}$l $a$a {expand}$l $a$a {expand}$l}}]} {
                error "An error was expected in the previous statement"
            }
            # Many words
            set l [run {list {expand}$l $a$a {expand}$l $a$a \
                                 {expand}$l $a$a {expand}$l $a$a \
                                 {expand}$l $a$a {expand}$l $a$a \
                                 {expand}$l $a$a {expand}$l $a$a \
                                 {expand}$l $a$a {expand}$l $a$a \
                                 {expand}$l $a$a {expand}$l $a$a \
                                 {expand}$l $a$a {expand}$l $a$a \
                                 {expand}$l $a$a {expand}$l $a$a \
                                 {expand}$l $a$a {expand}$l $a$a \
                                 {expand}$l $a$a}]

            if {[llength $l] != 19*28} {
                error "Bad Length: [llength $l] should be [expr {19*28}]"
            }
        }
    } -constraints [linsert $constraints 0 memory] -body {
        set end [getbytes]
        for {set i 0} {$i < 5} {incr i} {
            stress
            set tmp $end
            set end [getbytes]
        }    
        set leak [expr {$end - $tmp}]
    } -cleanup {
	unset end i tmp
	rename getbytes {}
	rename stress {}
} -result 0

test basic-48.17.$noComp {expansion: object safety} -setup {
        set old_precision $::tcl_precision
        set ::tcl_precision 4
    } -constraints $constraints -body { 
            set third [expr {1.0/3.0}]
            set l [list $third $third]
            set x [run {list $third {expand}$l $third}]
	    set res [list]
            foreach t $x {
                lappend res [expr {$t * 3.0}]
            }
            set res
    } -cleanup {
        set ::tcl_precision $old_precision
        unset old_precision res t l x third
} -result {1.0 1.0 1.0 1.0}

test basic-48.18.$noComp {expansion: list semantics} -constraints $constraints -body {
        set badcmd {
            list a b
            set apa 10
        }
        set apa 0
        list [llength [run { {expand}$badcmd }]] $apa
    } -cleanup {
	unset apa badcmd
} -result {5 0}

test basic-48.19.$noComp {expansion: error checking order} -body {
        set badlist "a {}x y"
        set a 0
        set b 0
        catch {run {list [incr a] {expand}$badlist [incr b]}}
        list $a $b
    } -constraints $constraints -cleanup {
	unset badlist a b
} -result {1 0}

test basic-48.20.$noComp {expansion: odd case with word boundaries} $constraints {
    run {list {expand}$::l1 {expand}"hej hopp" {expand}$::l2}
} {a {b b} c d hej hopp e f {g g} h}

test basic-48.21.$noComp {expansion: odd case with word boundaries} $constraints {
    run {list {expand}$::l1 {expand}{hej hopp} {expand}$::l2}
} {a {b b} c d hej hopp e f {g g} h}

test basic-48.22.$noComp {expansion: odd case with word boundaries} -body {
    run {list {expand}$::l1 {expand}"hej hopp {expand}$::l2}
} -constraints $constraints -returnCodes error -result {missing "}

test basic-48.23.$noComp {expansion: handle return codes} -constraints $constraints -body {
        set res {}
        for {set t 0} {$t < 10} {incr t} {
            run { {expand}break }
        }
        lappend res $t

        for {set t 0} {$t < 10} {incr t} {
            run { {expand}continue }
            set t 20
        }
        lappend res $t

        lappend res [catch { run { {expand}{error Hejsan} } } err]
        lappend res $err
    } -cleanup {
	unset res t
} -result {0 10 1 Hejsan}

} ;# End of noComp loop

# Clean up after expand tests
unset noComp l1 l2 constraints
rename l3 {}
rename run {}

 #cleanup
catch {namespace delete {expand}[namespace children :: test_ns_*]}
catch {namespace delete george}
catch {interp delete test_interp}
catch {rename p ""}
catch {rename q ""}
catch {rename cmd ""}
catch {rename value:at: ""}
catch {unset x}
::tcltest::cleanupTests
return
Changes to tests/binary.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# This file tests the tclBinary.c file and the "binary" Tcl command. 
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1997 by 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.
#
# RCS: @(#) $Id: binary.test,v 1.11.4.1 2003/08/07 21:36:04 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

test binary-0.1 {DupByteArrayInternalRep} {












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# This file tests the tclBinary.c file and the "binary" Tcl command. 
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1997 by 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.
#
# RCS: @(#) $Id: binary.test,v 1.11.4.2 2004/02/07 05:48:02 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

test binary-0.1 {DupByteArrayInternalRep} {
1511
1512
1513
1514
1515
1516
1517








1518
1519
1520
1521
    set y [binary format a* $x]
    list $x $y
} "\u00a4 \u00a4"
test binary-46.5 {Tcl_BinaryObjCmd: handling of non-ISO8859-1 chars} {
    set x [binary scan \u00a4 a* y]
    list $x $y [encoding convertfrom iso8859-15 $y]
} "1 \u00a4 \u20ac"









# cleanup
::tcltest::cleanupTests
return







>
>
>
>
>
>
>
>




1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
    set y [binary format a* $x]
    list $x $y
} "\u00a4 \u00a4"
test binary-46.5 {Tcl_BinaryObjCmd: handling of non-ISO8859-1 chars} {
    set x [binary scan \u00a4 a* y]
    list $x $y [encoding convertfrom iso8859-15 $y]
} "1 \u00a4 \u20ac"

test binary-47.1 {Tcl_BinaryObjCmd: number cache reference count handling} {
    # This test is only reliable when memory debugging is turned on,
    # but without even memory debugging it should still generate the
    # expected answers and might therefore still pick up memory corruption
    # caused by [Bug 851747].
    list [binary scan aba ccc x x x] $x
} {3 97}

# cleanup
::tcltest::cleanupTests
return
Changes to tests/cmdIL.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
# This file contains a collection of tests for the procedures in the
# file tclCmdIL.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.
#
# RCS: @(#) $Id: cmdIL.test,v 1.14.8.2 2003/10/16 02:28:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}




test cmdIL-1.1 {Tcl_LsortObjCmd procedure} {
    list [catch {lsort} msg] $msg
} {1 {wrong # args: should be "lsort ?options? list"}}
test cmdIL-1.2 {Tcl_LsortObjCmd procedure} {
    list [catch {lsort -foo {1 3 2 5}} msg] $msg
} {1 {bad option "-foo": must be -ascii, -command, -decreasing, -dictionary, -increasing, -index, -integer, -real, or -unique}}
test cmdIL-1.3 {Tcl_LsortObjCmd procedure, default options} {
    lsort {d e c b a \{ d35 d300}
} {a b c d d300 d35 e \{}
test cmdIL-1.4 {Tcl_LsortObjCmd procedure, -ascii option} {
    lsort -integer -ascii {d e c b a d35 d300}
} {a b c d d300 d35 e}
test cmdIL-1.5 {Tcl_LsortObjCmd procedure, -command option} {
    list [catch {lsort -command {1 3 2 5}} msg] $msg
} {1 {"-command" option must be followed by comparison command}}
test cmdIL-1.6 {Tcl_LsortObjCmd procedure, -command option} {
    proc cmp {a b} {
	expr {[string match x* $b] - [string match x* $a]}
    }

    lsort -command cmp {x1 abc x2 def x3 x4}
} {x1 x2 x3 x4 abc def}


test cmdIL-1.7 {Tcl_LsortObjCmd procedure, -decreasing option} {
    lsort -decreasing {d e c b a d35 d300}
} {e d35 d300 d c b a}
test cmdIL-1.8 {Tcl_LsortObjCmd procedure, -dictionary option} {
    lsort -dictionary {d e c b a d35 d300}
} {a b c d d35 d300 e}
test cmdIL-1.9 {Tcl_LsortObjCmd procedure, -dictionary option} {










|


|



>
>
>















|



>

|
>
>







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
# This file contains a collection of tests for the procedures in the
# file tclCmdIL.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.
#
# RCS: @(#) $Id: cmdIL.test,v 1.14.8.3 2004/02/07 05:48:02 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# Used for constraining memory leak tests
testConstraint memory [llength [info commands memory]]

test cmdIL-1.1 {Tcl_LsortObjCmd procedure} {
    list [catch {lsort} msg] $msg
} {1 {wrong # args: should be "lsort ?options? list"}}
test cmdIL-1.2 {Tcl_LsortObjCmd procedure} {
    list [catch {lsort -foo {1 3 2 5}} msg] $msg
} {1 {bad option "-foo": must be -ascii, -command, -decreasing, -dictionary, -increasing, -index, -integer, -real, or -unique}}
test cmdIL-1.3 {Tcl_LsortObjCmd procedure, default options} {
    lsort {d e c b a \{ d35 d300}
} {a b c d d300 d35 e \{}
test cmdIL-1.4 {Tcl_LsortObjCmd procedure, -ascii option} {
    lsort -integer -ascii {d e c b a d35 d300}
} {a b c d d300 d35 e}
test cmdIL-1.5 {Tcl_LsortObjCmd procedure, -command option} {
    list [catch {lsort -command {1 3 2 5}} msg] $msg
} {1 {"-command" option must be followed by comparison command}}
test cmdIL-1.6 {Tcl_LsortObjCmd procedure, -command option} -setup {
    proc cmp {a b} {
	expr {[string match x* $b] - [string match x* $a]}
    }
} -body {
    lsort -command cmp {x1 abc x2 def x3 x4}
} -result {x1 x2 x3 x4 abc def} -cleanup {
    rename cmp ""
}
test cmdIL-1.7 {Tcl_LsortObjCmd procedure, -decreasing option} {
    lsort -decreasing {d e c b a d35 d300}
} {e d35 d300 d c b a}
test cmdIL-1.8 {Tcl_LsortObjCmd procedure, -dictionary option} {
    lsort -dictionary {d e c b a d35 d300}
} {a b c d d35 d300 e}
test cmdIL-1.9 {Tcl_LsortObjCmd procedure, -dictionary option} {
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
test cmdIL-1.22 {Tcl_LsortObjCmd procedure, unique sort} {
    lsort -integer -unique {3 1 2 3 1 4 3}
} {1 2 3 4}
test cmdIL-1.23 {Tcl_LsortObjCmd procedure, unique sort with index} {
    # lsort -unique should return the last unique item
    lsort -unique -index 0 {{a b} {c b} {a c} {d a}}
} {{a c} {c b} {d a}}
test cmdIL-1.24 {Tcl_LsortObjCmd procedure, order of -index and -command} {
    catch {rename 1 ""}
    proc testcmp {a b} {return [string compare $a $b]}

    set l [list [list a b] [list c d]]
    set result [list [catch {lsort -command testcmp -index 1 $l} msg] $msg]

    rename testcmp ""
    set result
} [list 0 [list [list a b] [list c d]]]
test cmdIL-1.25 {Tcl_LsortObjCmd procedure, order of -index and -command} {
    catch {rename 1 ""}
    proc testcmp {a b} {return [string compare $a $b]}

    set l [list [list a b] [list c d]]
    set result [list [catch {lsort -index 1 -command testcmp $l} msg] $msg]

    rename testcmp ""
    set result
} [list 0 [list [list a b] [list c d]]]
# Note that the required order only exists in the end-1'th element;
# indexing using the end element or any fixed offset from the start
# will not work...
test cmdIL-1.26 {Tcl_LsortObjCmd procedure, offset indexing from end} {
    lsort -index end-1 {{a 1 e i} {b 2 3 f g} {c 4 5 6 d h}}
} {{c 4 5 6 d h} {a 1 e i} {b 2 3 f g}}

# Can't think of any good tests for the MergeSort and MergeLists
# procedures, except a bunch of random lists to sort.

test cmdIL-2.1 {MergeSort and MergeLists procedures} {
    set result {}
    set r 1435753299
    proc rand {} {
	global r
	set r [expr {(16807 * $r) % (0x7fffffff)}]
    }

    for {set i 0} {$i < 150} {incr i} {
	set x {}
	for {set j 0} {$j < $i} {incr j} {
	    lappend x [expr {[rand] & 0xfff}]
	}
	set y [lsort -integer $x]
	set old -1
	foreach el $y {
	    if {$el < $old} {
		append result "list {$x} sorted to {$y}, element $el out of order\n"
		break
	    }
	    set old $el
	}
    }
    set result
} {}



test cmdIL-3.1 {SortCompare procedure, skip comparisons after error} {
    set x 0
    proc cmp {a b} {
	global x
	incr x
	error "error #$x"
    }


    list [catch {lsort -integer -command cmp {48 6 28 190 16 2 3 6 1}} msg] \
	    $msg $x


} {1 {error #1} 1}
test cmdIL-3.2 {SortCompare procedure, -index option} {
    list [catch {lsort -integer -index 2 "\\\{ {30 40 50}"} msg] $msg
} {1 {unmatched open brace in list}}
test cmdIL-3.3 {SortCompare procedure, -index option} {
    list [catch {lsort -integer -index 2 {{20 10} {15 30 40}}} msg] $msg
} {1 {element 2 missing from sublist "20 10"}}
test cmdIL-3.4 {SortCompare procedure, -index option} {







|


>

|
>

<
|
|


>

|
>

<
|










|






>
















|
>
>

|
<





>
>


>
>
|







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
test cmdIL-1.22 {Tcl_LsortObjCmd procedure, unique sort} {
    lsort -integer -unique {3 1 2 3 1 4 3}
} {1 2 3 4}
test cmdIL-1.23 {Tcl_LsortObjCmd procedure, unique sort with index} {
    # lsort -unique should return the last unique item
    lsort -unique -index 0 {{a b} {c b} {a c} {d a}}
} {{a c} {c b} {d a}}
test cmdIL-1.24 {Tcl_LsortObjCmd procedure, order of -index and -command} -setup {
    catch {rename 1 ""}
    proc testcmp {a b} {return [string compare $a $b]}
} -body {
    set l [list [list a b] [list c d]]
    list [catch {lsort -command testcmp -index 1 $l} msg] $msg
} -cleanup {
    rename testcmp ""

} -result [list 0 [list [list a b] [list c d]]]
test cmdIL-1.25 {Tcl_LsortObjCmd procedure, order of -index and -command} -setup {
    catch {rename 1 ""}
    proc testcmp {a b} {return [string compare $a $b]}
} -body {
    set l [list [list a b] [list c d]]
    list [catch {lsort -index 1 -command testcmp $l} msg] $msg
} -cleanup {
    rename testcmp ""

} -result [list 0 [list [list a b] [list c d]]]
# Note that the required order only exists in the end-1'th element;
# indexing using the end element or any fixed offset from the start
# will not work...
test cmdIL-1.26 {Tcl_LsortObjCmd procedure, offset indexing from end} {
    lsort -index end-1 {{a 1 e i} {b 2 3 f g} {c 4 5 6 d h}}
} {{c 4 5 6 d h} {a 1 e i} {b 2 3 f g}}

# Can't think of any good tests for the MergeSort and MergeLists
# procedures, except a bunch of random lists to sort.

test cmdIL-2.1 {MergeSort and MergeLists procedures} -setup {
    set result {}
    set r 1435753299
    proc rand {} {
	global r
	set r [expr {(16807 * $r) % (0x7fffffff)}]
    }
} -body {
    for {set i 0} {$i < 150} {incr i} {
	set x {}
	for {set j 0} {$j < $i} {incr j} {
	    lappend x [expr {[rand] & 0xfff}]
	}
	set y [lsort -integer $x]
	set old -1
	foreach el $y {
	    if {$el < $old} {
		append result "list {$x} sorted to {$y}, element $el out of order\n"
		break
	    }
	    set old $el
	}
    }
    set result
} -cleanup {
    rename rand ""
} -result {}

test cmdIL-3.1 {SortCompare procedure, skip comparisons after error} -setup {

    proc cmp {a b} {
	global x
	incr x
	error "error #$x"
    }
} -body {
    set x 0
    list [catch {lsort -integer -command cmp {48 6 28 190 16 2 3 6 1}} msg] \
	    $msg $x
} -cleanup {
    rename cmp ""
} -result {1 {error #1} 1}
test cmdIL-3.2 {SortCompare procedure, -index option} {
    list [catch {lsort -integer -index 2 "\\\{ {30 40 50}"} msg] $msg
} {1 {unmatched open brace in list}}
test cmdIL-3.3 {SortCompare procedure, -index option} {
    list [catch {lsort -integer -index 2 {{20 10} {15 30 40}}} msg] $msg
} {1 {element 2 missing from sublist "20 10"}}
test cmdIL-3.4 {SortCompare procedure, -index option} {
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
} {1 {expected floating-point number but got "6...4"}}
test cmdIL-3.13 {SortCompare procedure, -real option} {
    list [catch {lsort -real {3 1x7}} msg] $msg
} {1 {expected floating-point number but got "1x7"}}
test cmdIL-3.14 {SortCompare procedure, -real option} {
    lsort -real {24 2.5e01 16.7 85e-1 10.004}
} {85e-1 10.004 16.7 24 2.5e01}
test cmdIL-3.15 {SortCompare procedure, -command option} {
    proc cmp {a b} {
	error "comparison error"
    }
    list [catch {lsort -command cmp {48 6}} msg] $msg $errorInfo


} {1 {comparison error} {comparison error
    while executing
"error "comparison error""
    (procedure "cmp" line 2)
    invoked from within
"cmp 48 6"
    (-compare command)
    invoked from within
"lsort -command cmp {48 6}"}}
test cmdIL-3.16 {SortCompare procedure, -command option, long command} {
    proc cmp {dummy a b} {
	string compare $a $b
    }
    lsort -command {cmp {this argument is very very long in order to make the dstring overflow its statically allocated space}} {{this first element is also long in order to help expand the dstring} {the second element, last but not least, is quite long also, in order to make absolutely sure that space is allocated dynamically for the dstring}}


} {{the second element, last but not least, is quite long also, in order to make absolutely sure that space is allocated dynamically for the dstring} {this first element is also long in order to help expand the dstring}}
test cmdIL-3.17 {SortCompare procedure, -command option, non-integer result} {
    proc cmp {a b} {
	return foow
    }
    list [catch {lsort -command cmp {48 6}} msg] $msg


} {1 {-compare command returned non-integer result}}
test cmdIL-3.18 {SortCompare procedure, -command option} {
    proc cmp {a b} {
	expr {$b - $a}
    }
    lsort -command cmp {48 6 18 22 21 35 36}


} {48 36 35 22 21 18 6}
test cmdIL-3.19 {SortCompare procedure, -decreasing option} {
    lsort -decreasing -integer {35 21 0x20 30 023 100 8}
} {100 35 0x20 30 21 023 8}

test cmdIL-4.1 {DictionaryCompare procedure, numerics, leading zeros} {
    lsort -dictionary {a003b a03b}
} {a03b a003b}







|




>
>
|








|




>
>
|
|




>
>
|
|




>
>
|







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
} {1 {expected floating-point number but got "6...4"}}
test cmdIL-3.13 {SortCompare procedure, -real option} {
    list [catch {lsort -real {3 1x7}} msg] $msg
} {1 {expected floating-point number but got "1x7"}}
test cmdIL-3.14 {SortCompare procedure, -real option} {
    lsort -real {24 2.5e01 16.7 85e-1 10.004}
} {85e-1 10.004 16.7 24 2.5e01}
test cmdIL-3.15 {SortCompare procedure, -command option} -body {
    proc cmp {a b} {
	error "comparison error"
    }
    list [catch {lsort -command cmp {48 6}} msg] $msg $errorInfo
} -cleanup {
    rename cmp ""
} -result {1 {comparison error} {comparison error
    while executing
"error "comparison error""
    (procedure "cmp" line 2)
    invoked from within
"cmp 48 6"
    (-compare command)
    invoked from within
"lsort -command cmp {48 6}"}}
test cmdIL-3.16 {SortCompare procedure, -command option, long command} -body {
    proc cmp {dummy a b} {
	string compare $a $b
    }
    lsort -command {cmp {this argument is very very long in order to make the dstring overflow its statically allocated space}} {{this first element is also long in order to help expand the dstring} {the second element, last but not least, is quite long also, in order to make absolutely sure that space is allocated dynamically for the dstring}}
} -cleanup {
    rename cmp ""
} -result {{the second element, last but not least, is quite long also, in order to make absolutely sure that space is allocated dynamically for the dstring} {this first element is also long in order to help expand the dstring}}
test cmdIL-3.17 {SortCompare procedure, -command option, non-integer result} -body {
    proc cmp {a b} {
	return foow
    }
    list [catch {lsort -command cmp {48 6}} msg] $msg
} -cleanup {
    rename cmp ""
} -result {1 {-compare command returned non-integer result}}
test cmdIL-3.18 {SortCompare procedure, -command option} -body {
    proc cmp {a b} {
	expr {$b - $a}
    }
    lsort -command cmp {48 6 18 22 21 35 36}
} -cleanup {
    rename cmp ""
} -result {48 36 35 22 21 18 6}
test cmdIL-3.19 {SortCompare procedure, -decreasing option} {
    lsort -decreasing -integer {35 21 0x20 30 023 100 8}
} {100 35 0x20 30 21 023 8}

test cmdIL-4.1 {DictionaryCompare procedure, numerics, leading zeros} {
    lsort -dictionary {a003b a03b}
} {a03b a003b}
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396



397



































































































































































































































































































398
399
400
401




	{the {0 1 2 3 4 5} quick}
	{brown {0 1 2 3 4} fox}
	{jumps {30 31 2 33} over}
	{the {0 1 2} lazy}
	{dogs {0 1}}
    }
} {{dogs {0 1}} {the {0 1 2} lazy} {jumps {30 31 2 33} over} {brown {0 1 2 3 4} fox} {the {0 1 2 3 4 5} quick}}
test cmdIL-5.5 {lsort with list style index and sharing} {
    proc test {l} {
	set n $l
	foreach e $l {lappend n [list [expr {rand()}] $e]}
	lindex [lsort -real -index $l $n] 1 1
    }
    expr srand(1)
    test 0



} 0




































































































































































































































































































# cleanup
::tcltest::cleanupTests
return











|
|





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




>
>
>
>
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
	{the {0 1 2 3 4 5} quick}
	{brown {0 1 2 3 4} fox}
	{jumps {30 31 2 33} over}
	{the {0 1 2} lazy}
	{dogs {0 1}}
    }
} {{dogs {0 1}} {the {0 1 2} lazy} {jumps {30 31 2 33} over} {brown {0 1 2 3 4} fox} {the {0 1 2 3 4 5} quick}}
test cmdIL-5.5 {lsort with list style index and sharing} -body {
    proc test_lsort {l} {
	set n $l
	foreach e $l {lappend n [list [expr {rand()}] $e]}
	lindex [lsort -real -index $l $n] 1 1
    }
    expr srand(1)
    test_lsort 0
} -result 0 -cleanup {
    rename test_lsort ""
}

# Compiled version
test cmdIL-6.1 {lassign command syntax} -body {
    proc testLassign {} {
	lassign
    }
    testLassign
} -returnCodes 1 -cleanup {
    rename testLassign {}
} -result {wrong # args: should be "lassign list varname ?varname ...?"}
test cmdIL-6.2 {lassign command syntax} -body {
    proc testLassign {} {
	lassign x
    }
    testLassign
} -returnCodes 1 -cleanup {
    rename testLassign {}
} -result {wrong # args: should be "lassign list varname ?varname ...?"}
test cmdIL-6.3 {lassign command} -body {
    proc testLassign {} {
	set x FAIL
	list [lassign a x] $x
    }
    testLassign
} -result {{} a} -cleanup {
    rename testLassign {}
}
test cmdIL-6.4 {lassign command} -body {
    proc testLassign {} {
	set x FAIL
	set y FAIL
	list [lassign a x y] $x $y
    }
    testLassign
} -result {{} a {}} -cleanup {
    rename testLassign {}
}
test cmdIL-6.5 {lassign command} -body {
    proc testLassign {} {
	set x FAIL
	set y FAIL
	list [lassign {a b} x y] $x $y
    }
    testLassign
} -result {{} a b} -cleanup {
    rename testLassign {}
}
test cmdIL-6.6 {lassign command} -body {
    proc testLassign {} {
	set x FAIL
	set y FAIL
	list [lassign {a b c} x y] $x $y
    }
    testLassign
} -result {c a b} -cleanup {
    rename testLassign {}
}
test cmdIL-6.7 {lassign command} -body {
    proc testLassign {} {
	set x FAIL
	set y FAIL
	list [lassign {a b c d} x y] $x $y
    }
    testLassign
} -result {{c d} a b} -cleanup {
    rename testLassign {}
}
test cmdIL-6.8 {lassign command - list format error} -body {
    proc testLassign {} {
	set x FAIL
	set y FAIL
	list [catch {lassign {a {b}c d} x y} msg] $msg $x $y
    }
    testLassign
} -result {1 {list element in braces followed by "c" instead of space} FAIL FAIL} -cleanup {
    rename testLassign {}
}
test cmdIL-6.9 {lassign command - assignment to arrays} -body {
    proc testLassign {} {
	list [lassign {a b} x(x)] $x(x)
    }
    testLassign
} -result {b a} -cleanup {
    rename testLassign {}
}
test cmdIL-6.10 {lassign command - variable update error} -body {
    proc testLassign {} {
	set x(x) {}
	lassign a x
    }
    testLassign
} -returnCodes 1 -result {can't set "x": variable is array} -cleanup {
    rename testLassign {}
}
test cmdIL-6.11 {lassign command - variable update error} -body {
    proc testLassign {} {
	set x(x) {}
	set y FAIL
	list [catch {lassign a y x} msg] $msg $y
    }
    testLassign
} -result {1 {can't set "x": variable is array} a} -cleanup {
    rename testLassign {}
}
test cmdIL-6.12 {lassign command - memory leak testing} -setup {
    unset -nocomplain x y
    set x(x) {}
    set y FAIL
    proc getbytes {} {
        set lines [split [memory info] "\n"]
        lindex [lindex $lines 3] 3
    }
    proc stress {} {
	global x y
	lassign {} y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
	catch {lassign {} y y y y y y y y y y y y y y y y y y y y y y y y y x}
	catch {lassign {} x}
    }
} -constraints memory -body {
    set end [getbytes]
    for {set i 0} {$i < 5} {incr i} {
	stress
	set tmp $end
	set end [getbytes]
    }
    expr {$end - $tmp}
} -result 0 -cleanup {
    unset -nocomplain x y i tmp end
    rename getbytes {}
    rename stress {}
}
# Force non-compiled version
test cmdIL-6.13 {lassign command syntax} -body {
    proc testLassign {} {
	set lassign lassign
	$lassign
    }
    testLassign
} -returnCodes 1 -cleanup {
    rename testLassign {}
} -result {wrong # args: should be "lassign list varname ?varname ...?"}
test cmdIL-6.14 {lassign command syntax} -body {
    proc testLassign {} {
	set lassign lassign
	$lassign x
    }
    testLassign
} -returnCodes 1 -cleanup {
    rename testLassign {}
} -result {wrong # args: should be "lassign list varname ?varname ...?"}
test cmdIL-6.15 {lassign command} -body {
    proc testLassign {} {
	set lassign lassign
	set x FAIL
	list [$lassign a x] $x
    }
    testLassign
} -result {{} a} -cleanup {
    rename testLassign {}
}
test cmdIL-6.16 {lassign command} -body {
    proc testLassign {} {
	set lassign lassign
	set x FAIL
	set y FAIL
	list [$lassign a x y] $x $y
    }
    testLassign
} -result {{} a {}} -cleanup {
    rename testLassign {}
}
test cmdIL-6.17 {lassign command} -body {
    proc testLassign {} {
	set lassign lassign
	set x FAIL
	set y FAIL
	list [$lassign {a b} x y] $x $y
    }
    testLassign
} -result {{} a b} -cleanup {
    rename testLassign {}
}
test cmdIL-6.18 {lassign command} -body {
    proc testLassign {} {
	set lassign lassign
	set x FAIL
	set y FAIL
	list [$lassign {a b c} x y] $x $y
    }
    testLassign
} -result {c a b} -cleanup {
    rename testLassign {}
}
test cmdIL-6.19 {lassign command} -body {
    proc testLassign {} {
	set lassign lassign
	set x FAIL
	set y FAIL
	list [$lassign {a b c d} x y] $x $y
    }
    testLassign
} -result {{c d} a b} -cleanup {
    rename testLassign {}
}
test cmdIL-6.20 {lassign command - list format error} -body {
    proc testLassign {} {
	set lassign lassign
	set x FAIL
	set y FAIL
	list [catch {$lassign {a {b}c d} x y} msg] $msg $x $y
    }
    testLassign
} -result {1 {list element in braces followed by "c" instead of space} FAIL FAIL} -cleanup {
    rename testLassign {}
}
test cmdIL-6.21 {lassign command - assignment to arrays} -body {
    proc testLassign {} {
	set lassign lassign
	list [$lassign {a b} x(x)] $x(x)
    }
    testLassign
} -result {b a} -cleanup {
    rename testLassign {}
}
test cmdIL-6.22 {lassign command - variable update error} -body {
    proc testLassign {} {
	set lassign lassign
	set x(x) {}
	$lassign a x
    }
    testLassign
} -returnCodes 1 -result {can't set "x": variable is array} -cleanup {
    rename testLassign {}
}
test cmdIL-6.23 {lassign command - variable update error} -body {
    proc testLassign {} {
	set lassign lassign
	set x(x) {}
	set y FAIL
	list [catch {$lassign a y x} msg] $msg $y
    }
    testLassign
} -result {1 {can't set "x": variable is array} a} -cleanup {
    rename testLassign {}
}
test cmdIL-6.24 {lassign command - memory leak testing} -setup {
    set x(x) {}
    set y FAIL
    proc getbytes {} {
        set lines [split [memory info] "\n"]
        lindex [lindex $lines 3] 3
    }
    proc stress {} {
	global x y
	set lassign lassign
	$lassign {} y y y y y y y y y y y y y y y y y y y y y y y y y y y y y y
	catch {$lassign {} y y y y y y y y y y y y y y y y y y y y y y y y y x}
	catch {$lassign {} x}
    }
} -constraints memory -body {
    set end [getbytes]
    for {set i 0} {$i < 5} {incr i} {
	stress
	set tmp $end
	set end [getbytes]
    }
    expr {$end - $tmp}
} -result 0 -cleanup {
    unset -nocomplain x y i tmp end
    rename getbytes {}
    rename stress {}
}
# Assorted shimmering problems
test cmdIL-6.25 {lassign command - shimmering protection} -body {
    proc testLassign {} {
	set x {a b c}
	list [lassign $x $x y] $x [set $x] $y
    }
    testLassign
} -result {c {a b c} a b} -cleanup {
    rename testLassign {}
}
test cmdIL-6.26 {lassign command - shimmering protection} -body {
    proc testLassign {} {
	set x {a b c}
	set lassign lassign
	list [$lassign $x $x y] $x [set $x] $y
    }
    testLassign
} -result {c {a b c} a b} -cleanup {
    rename testLassign {}
}

# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:
Changes to tests/cmdInfo.test.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Copyright (c) 1993 The Regents of the University of California.
# Copyright (c) 1994-1996 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.
#
# RCS: @(#) $Id: cmdInfo.test,v 1.7 2002/06/22 04:19:47 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

::tcltest::testConstraint testcmdinfo \







|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Copyright (c) 1993 The Regents of the University of California.
# Copyright (c) 1994-1996 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.
#
# RCS: @(#) $Id: cmdInfo.test,v 1.7.4.1 2004/02/07 05:48:02 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

::tcltest::testConstraint testcmdinfo \
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

test cmdinfo-4.1 {Tcl_GetCommandName/Tcl_GetCommandFullName procedures} \
	{testcmdtoken} {
    set x [testcmdtoken create x1]
    rename x1 newName
    set y [testcmdtoken name $x]
    rename newName x1
    eval lappend y [testcmdtoken name $x]
} {newName ::newName x1 ::x1}

catch {rename newTestCmd {}}
catch {rename newTestCmd2 {}}

test cmdinfo-5.1 {Names for commands created when inside namespaces} \
	{testcmdtoken} {
    # create namespace cmdInfoNs1
    namespace eval cmdInfoNs1 {}   ;# creates namespace cmdInfoNs1
    # create namespace cmdInfoNs1::cmdInfoNs2 and execute a script in it
    set x [namespace eval cmdInfoNs1::cmdInfoNs2 {
        # the following creates a cmd in the global namespace
        testcmdtoken create testCmd
    }]
    set y [testcmdtoken name $x]
    rename ::testCmd newTestCmd
    eval lappend y [testcmdtoken name $x]
} {testCmd ::testCmd newTestCmd ::newTestCmd}

test cmdinfo-6.1 {Names for commands created when outside namespaces} \
	{testcmdtoken} {
    set x [testcmdtoken create cmdInfoNs1::cmdInfoNs2::testCmd]
    set y [testcmdtoken name $x]
    rename cmdInfoNs1::cmdInfoNs2::testCmd newTestCmd2
    eval lappend y [testcmdtoken name $x]
} {testCmd ::cmdInfoNs1::cmdInfoNs2::testCmd newTestCmd2 ::newTestCmd2}

# cleanup
catch {namespace delete cmdInfoNs1::cmdInfoNs2 cmdInfoNs1}
catch {rename x1 ""}
::tcltest::cleanupTests
return







|
















|







|







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

test cmdinfo-4.1 {Tcl_GetCommandName/Tcl_GetCommandFullName procedures} \
	{testcmdtoken} {
    set x [testcmdtoken create x1]
    rename x1 newName
    set y [testcmdtoken name $x]
    rename newName x1
    lappend y {expand}[testcmdtoken name $x]
} {newName ::newName x1 ::x1}

catch {rename newTestCmd {}}
catch {rename newTestCmd2 {}}

test cmdinfo-5.1 {Names for commands created when inside namespaces} \
	{testcmdtoken} {
    # create namespace cmdInfoNs1
    namespace eval cmdInfoNs1 {}   ;# creates namespace cmdInfoNs1
    # create namespace cmdInfoNs1::cmdInfoNs2 and execute a script in it
    set x [namespace eval cmdInfoNs1::cmdInfoNs2 {
        # the following creates a cmd in the global namespace
        testcmdtoken create testCmd
    }]
    set y [testcmdtoken name $x]
    rename ::testCmd newTestCmd
    lappend y {expand}[testcmdtoken name $x]
} {testCmd ::testCmd newTestCmd ::newTestCmd}

test cmdinfo-6.1 {Names for commands created when outside namespaces} \
	{testcmdtoken} {
    set x [testcmdtoken create cmdInfoNs1::cmdInfoNs2::testCmd]
    set y [testcmdtoken name $x]
    rename cmdInfoNs1::cmdInfoNs2::testCmd newTestCmd2
    lappend y {expand}[testcmdtoken name $x]
} {testCmd ::cmdInfoNs1::cmdInfoNs2::testCmd newTestCmd2 ::newTestCmd2}

# cleanup
catch {namespace delete cmdInfoNs1::cmdInfoNs2 cmdInfoNs1}
catch {rename x1 ""}
::tcltest::cleanupTests
return
Changes to tests/cmdMZ.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
# The tests in this file cover the procedures in tclCmdMZ.c.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1991-1993 The Regents of the University of California.
# Copyright (c) 1994 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.
#
# RCS: @(#) $Id: cmdMZ.test,v 1.15.2.2 2003/09/05 23:08:07 dgp Exp $

if {[catch {package require tcltest 2.0.2}]} {
    puts stderr "Skipping tests in [info script]. tcltest 2.0.2 required."
    return
}

namespace eval ::tcl::test::cmdMZ {
    namespace import ::tcltest::cleanupTests
    namespace import ::tcltest::makeFile
    namespace import ::tcltest::removeFile
    namespace import ::tcltest::temporaryDirectory
    namespace import ::tcltest::test

set ::tcltest::testConstraints(nonLinuxOnly) \
	[expr {![string equal Linux $tcl_platform(os)]}]

# Tcl_PwdObjCmd

test cmdMZ-1.1 {Tcl_PwdObjCmd} {
    list [catch {pwd a} msg] $msg
} {1 {wrong # args: should be "pwd"}}
test cmdMZ-1.2 {Tcl_PwdObjCmd: simple pwd} {
    catch pwd
} 0
test cmdMZ-1.3 {Tcl_PwdObjCmd: simple pwd} {
    expr [string length pwd]>0
} 1
test cmdMZ-1.4 {Tcl_PwdObjCmd: failure} {unixOnly nonLinuxOnly} {
    # We don't want this test to run on Linux because they do a
    # permissions caching trick which causes this to fail.  The
    # caching is incorrect, but we have no control over that.
    set foodir [file join [temporaryDirectory] foo]
    file delete -force $foodir
    file mkdir $foodir
    set cwd [pwd]
    cd $foodir
    file attr . -permissions 000
    set result [list [catch {pwd} msg] $msg]













|













<
<
<











|
|
|
|







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
# The tests in this file cover the procedures in tclCmdMZ.c.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1991-1993 The Regents of the University of California.
# Copyright (c) 1994 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.
#
# RCS: @(#) $Id: cmdMZ.test,v 1.15.2.3 2004/02/07 05:48:02 dgp Exp $

if {[catch {package require tcltest 2.0.2}]} {
    puts stderr "Skipping tests in [info script]. tcltest 2.0.2 required."
    return
}

namespace eval ::tcl::test::cmdMZ {
    namespace import ::tcltest::cleanupTests
    namespace import ::tcltest::makeFile
    namespace import ::tcltest::removeFile
    namespace import ::tcltest::temporaryDirectory
    namespace import ::tcltest::test




# Tcl_PwdObjCmd

test cmdMZ-1.1 {Tcl_PwdObjCmd} {
    list [catch {pwd a} msg] $msg
} {1 {wrong # args: should be "pwd"}}
test cmdMZ-1.2 {Tcl_PwdObjCmd: simple pwd} {
    catch pwd
} 0
test cmdMZ-1.3 {Tcl_PwdObjCmd: simple pwd} {
    expr [string length pwd]>0
} 1
test cmdMZ-1.4 {Tcl_PwdObjCmd: failure} {unixOnly nonPortable} {
    # This test fails on various unix platforms (eg Linux) where
    # permissions caching causes this to fail.  The caching is strictly
    # incorrect, but we have no control over that.
    set foodir [file join [temporaryDirectory] foo]
    file delete -force $foodir
    file mkdir $foodir
    set cwd [pwd]
    cd $foodir
    file attr . -permissions 000
    set result [list [catch {pwd} msg] $msg]
Changes to tests/compile.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# This file contains tests for the files tclCompile.c, tclCompCmds.c
# and tclLiteral.c
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1997 by 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.
#
# RCS: @(#) $Id: compile.test,v 1.27 2003/05/09 13:42:40 msofer Exp $

package require tcltest 2
namespace import -force ::tcltest::*

# The following tests are very incomplete, although the rest of the
# test suite covers this file fairly well.














|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# This file contains tests for the files tclCompile.c, tclCompCmds.c
# and tclLiteral.c
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1997 by 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.
#
# RCS: @(#) $Id: compile.test,v 1.27.2.1 2004/02/07 05:48:02 dgp Exp $

package require tcltest 2
namespace import -force ::tcltest::*

# The following tests are very incomplete, although the rest of the
# test suite covers this file fairly well.

270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# Special section for tests of tclLiteral.c
# The following tests check for incorrect memory handling in
# TclReleaseLiteral. They are only effective when tcl is compiled 
# with TCL_MEM_DEBUG
#
# Special test for leak on interp delete [Bug 467523]. 
::tcltest::testConstraint exec [llength [info commands exec]]
::tcltest::testConstraint memDebug [llength [info commands memory]]

test compile-12.1 {testing literal leak on interp delete} {memDebug} {
    proc getbytes {} {
	set lines [split [memory info] "\n"]
	lindex [lindex $lines 3] 3
    }
    
    set end [getbytes]
    for {set i 0} {$i < 5} {incr i} {







|

|







270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# Special section for tests of tclLiteral.c
# The following tests check for incorrect memory handling in
# TclReleaseLiteral. They are only effective when tcl is compiled 
# with TCL_MEM_DEBUG
#
# Special test for leak on interp delete [Bug 467523]. 
::tcltest::testConstraint exec [llength [info commands exec]]
::tcltest::testConstraint memory [llength [info commands memory]]

test compile-12.1 {testing literal leak on interp delete} {memory} {
    proc getbytes {} {
	set lines [split [memory info] "\n"]
	lindex [lindex $lines 3] 3
    }
    
    set end [getbytes]
    for {set i 0} {$i < 5} {incr i} {
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
    }    
    rename getbytes {}
    set leak [expr {$end - $tmp}]
} 0
# Special test for a memory error in a preliminary fix of [Bug 467523]. 
# It requires executing a helpfile.  Presumably the child process is
# used because when this test fails, it crashes.
test compile-12.2 {testing error on literal deletion} {memDebug exec} {
    makeFile {
	for {set i 0} {$i < 5} {incr i} {
	    namespace eval bar {}
	    namespace delete bar
	}
	puts 0
    } source.file







|







294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
    }    
    rename getbytes {}
    set leak [expr {$end - $tmp}]
} 0
# Special test for a memory error in a preliminary fix of [Bug 467523]. 
# It requires executing a helpfile.  Presumably the child process is
# used because when this test fails, it crashes.
test compile-12.2 {testing error on literal deletion} {memory exec} {
    makeFile {
	for {set i 0} {$i < 5} {incr i} {
	    namespace eval bar {}
	    namespace delete bar
	}
	puts 0
    } source.file
369
370
371
372
373
374
375













































































































































376
377
378
379
380
381
382
383
384
test compile-15.5 {proper TCL_RETURN code from [return]} {
    proc p {} {catch {set a 1}; return}
    set result [p]
    rename p {}
    set result
} ""















































































































































# cleanup
catch {rename p ""}
catch {namespace delete test_ns_compile}
catch {unset x}
catch {unset y}
catch {unset a}
::tcltest::cleanupTests
return







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









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
test compile-15.5 {proper TCL_RETURN code from [return]} {
    proc p {} {catch {set a 1}; return}
    set result [p]
    rename p {}
    set result
} ""

testConstraint testevalex [llength [info commands testevalex]]
for {set noComp 0} {$noComp <= 1} {incr noComp} {

if $noComp {
    interp alias {} run {} testevalex
    set constraints testevalex
} else {
    interp alias {} run {} if 1
    set constraints {}
}

test compile-16.1.$noComp {TclCompileScript: word expansion} $constraints {
    run "list [string repeat {{expand}a } 255]"
} [lrepeat 255 a]

test compile-16.2.$noComp {TclCompileScript: word expansion} $constraints {
    run "list [string repeat {{expand}a } 256]"
} [lrepeat 256 a]

test compile-16.3.$noComp {TclCompileScript: word expansion} $constraints {
    run "list [string repeat {{expand}a } 257]"
} [lrepeat 257 a]

test compile-16.4.$noComp {TclCompileScript: word expansion} $constraints {
    run {{expand}list}
} {}

test compile-16.5.$noComp {TclCompileScript: word expansion} $constraints {
    run {{expand}list {expand}{x y z}}
} {x y z}

test compile-16.6.$noComp {TclCompileScript: word expansion} $constraints {
    run {{expand}list {expand}[list x y z]}
} {x y z}

test compile-16.7.$noComp {TclCompileScript: word expansion} $constraints {
    run {{expand}list {expand}[list x y z][list x y z]}
} {x y zx y z}

test compile-16.8.$noComp {TclCompileScript: word expansion} -body {
    set l {x y z}
    run {{expand}list {expand}$l}
} -constraints $constraints -cleanup {
    unset l
} -result {x y z}

test compile-16.9.$noComp {TclCompileScript: word expansion} -body {
    set l {x y z}
    run {{expand}list {expand}$l$l}
} -constraints $constraints -cleanup {
    unset l
} -result {x y zx y z}

test compile-16.10.$noComp {TclCompileScript: word expansion} -body {
    run {{expand}\{}
} -constraints $constraints -returnCodes error \
-result {unmatched open brace in list}

test compile-16.11.$noComp {TclCompileScript: word expansion} -body {
    proc badList {} {return \{}
    run {{expand}[badList]}
} -constraints $constraints -cleanup {
    rename badList {}
} -returnCodes error  -result {unmatched open brace in list}

test compile-16.12.$noComp {TclCompileScript: word expansion} $constraints {
    run {{expand}list x y z}
} {x y z}

test compile-16.13.$noComp {TclCompileScript: word expansion} $constraints {
    run {{expand}list x y {expand}z}
} {x y z}

test compile-16.14.$noComp {TclCompileScript: word expansion} $constraints {
    run {{expand}list x {expand}y z}
} {x y z}

test compile-16.15.$noComp {TclCompileScript: word expansion} $constraints {
    run {list x y {expand}z}
} {x y z}

test compile-16.16.$noComp {TclCompileScript: word expansion} $constraints {
    run {list x {expand}y z}
} {x y z}

test compile-16.17.$noComp {TclCompileScript: word expansion} $constraints {
    run {list {expand}x y z}
} {x y z}

# These tests note that expansion can in theory cause the number of
# arguments to a command to exceed INT_MAX, which is as big as objc
# is allowed to get.
#
# In practice, it seems we will run out of memory before we confront
# this issue.  Note that compiled operations run out of memory at
# smaller objc values than direct string evaluation.
#
# These tests are constrained as knownBug because they are likely
# to cause memory allocation panics somewhere, and we don't want
# panics in the test suite.
#
test compile-16.18.$noComp {TclCompileScript: word expansion} -body {
    proc LongList {} {return [lrepeat [expr {1<<10}] x]}
    llength [run "list [string repeat {{expand}[LongList] } [expr {1<<10}]]"]
} -constraints [linsert $constraints 0 knownBug] -cleanup {
    rename LongList {}
} -returnCodes ok  -result [expr {1<<20}]

test compile-16.19.$noComp {TclCompileScript: word expansion} -body {
    proc LongList {} {return [lrepeat [expr {1<<11}] x]}
    llength [run "list [string repeat {{expand}[LongList] } [expr {1<<11}]]"]
} -constraints [linsert $constraints 0 knownBug] -cleanup {
    rename LongList {}
} -returnCodes ok  -result [expr {1<<22}]

test compile-16.20.$noComp {TclCompileScript: word expansion} -body {
    proc LongList {} {return [lrepeat [expr {1<<12}] x]}
    llength [run "list [string repeat {{expand}[LongList] } [expr {1<<12}]]"]
} -constraints [linsert $constraints 0 knownBug] -cleanup {
    rename LongList {}
} -returnCodes ok  -result [expr {1<<24}]

# This is the one that should cause overflow
test compile-16.21.$noComp {TclCompileScript: word expansion} -body {
    proc LongList {} {return [lrepeat [expr {1<<16}] x]}
    llength [run "list [string repeat {{expand}[LongList] } [expr {1<<16}]]"]
} -constraints [linsert $constraints 0 knownBug] -cleanup {
    rename LongList {}
} -returnCodes ok  -result [expr {wide(1)<<32}]

test compile-16.22.$noComp {
    Bug 845412: TclCompileScript: word expansion not mandatory
} -body {
    # This test may crash and will fail unless Bug 845412 is fixed.
    proc ReturnResults args {return $args}
    run "ReturnResults [string repeat {x } 260]"
} -constraints $constraints -cleanup {
    rename ReturnResults {}
} -returnCodes ok -result [string trim [string repeat {x } 260]]

}	;# End of noComp loop

# cleanup
catch {rename p ""}
catch {namespace delete test_ns_compile}
catch {unset x}
catch {unset y}
catch {unset a}
::tcltest::cleanupTests
return
Changes to tests/dict.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
# This test file covers the dictionary object type and the dict
# command used to work with values of that type.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands. Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 2003 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: dict.test,v 1.2.2.2 2003/10/16 02:28:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}




# Procedure to help check the contents of a dictionary.  Note that we
# can't just compare the string version because the order of the
# elements is (deliberately) not defined.  This is because it is
# dependent on the underlying hash table implementation and also
# potentially on the history of the value itself.  Net result: you
# cannot safely assume anything about the ordering of values.
proc getOrder {dictVal args} {











|






>
>
>







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
# This test file covers the dictionary object type and the dict
# command used to work with values of that type.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands. Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 2003 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: dict.test,v 1.2.2.3 2004/02/07 05:48:02 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# Used for constraining memory leak tests
testConstraint memory [llength [info commands memory]]

# Procedure to help check the contents of a dictionary.  Note that we
# can't just compare the string version because the order of the
# elements is (deliberately) not defined.  This is because it is
# dependent on the underlying hash table implementation and also
# potentially on the history of the value itself.  Net result: you
# cannot safely assume anything about the ordering of values.
proc getOrder {dictVal args} {
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
    list [catch {dict create a} msg] $msg
} {1 {wrong # args: should be "dict create ?key value ...?"}}
test dict-2.5 {dict create command} {
    list [catch {dict create a b c} msg] $msg
} {1 {wrong # args: should be "dict create ?key value ...?"}}
test dict-2.6 {dict create command - initialse refcount field!} {
    # Bug 715751 will show up in memory debuggers like purify
    for {set i 0} {$i<10} {incr i} { 
	set dictv [dict create a 0] 
	set share [dict values $dictv] 
	list [dict incr dictv a] 
    } 
} {}
test dict-2.7 {dict create command - #-quoting in string rep} {
    dict create # #comment
} {{#} #comment}
test dict-2.8 {dict create command - #-quoting in string rep} -body {
    dict create #a x #b x
} -match glob -result {{#?} x #? x}







|
|
|
|
|







63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
    list [catch {dict create a} msg] $msg
} {1 {wrong # args: should be "dict create ?key value ...?"}}
test dict-2.5 {dict create command} {
    list [catch {dict create a b c} msg] $msg
} {1 {wrong # args: should be "dict create ?key value ...?"}}
test dict-2.6 {dict create command - initialse refcount field!} {
    # Bug 715751 will show up in memory debuggers like purify
    for {set i 0} {$i<10} {incr i} {
	set dictv [dict create a 0]
	set share [dict values $dictv]
	list [dict incr dictv a]
    }
} {}
test dict-2.7 {dict create command - #-quoting in string rep} {
    dict create # #comment
} {{#} #comment}
test dict-2.8 {dict create command - #-quoting in string rep} -body {
    dict create #a x #b x
} -match glob -result {{#?} x #? x}
132
133
134
135
136
137
138

139
140
141
142
143
144
145
test dict-4.7 {dict replace command} {
    list [catch {dict replace {a a a} a b} msg] $msg
} {1 {missing value to go with key}}
test dict-4.8 {dict replace command} {
    list [catch {dict replace [list a a a] a b} msg] $msg
} {1 {missing value to go with key}}
test dict-4.9 {dict replace command} {dict replace [list a a] a b} {a b}


test dict-5.1 {dict remove command} {dict remove {a b c d} a} {c d}
test dict-5.2 {dict remove command} {dict remove {a b c d} c} {a b}
test dict-5.3 {dict remove command} {dict remove {a b c d} a c} {}
test dict-5.4 {dict remove command} {dict remove {a b c d} c a} {}
test dict-5.5 {dict remove command} {
    getOrder [dict remove {a b c d}] a c







>







135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
test dict-4.7 {dict replace command} {
    list [catch {dict replace {a a a} a b} msg] $msg
} {1 {missing value to go with key}}
test dict-4.8 {dict replace command} {
    list [catch {dict replace [list a a a] a b} msg] $msg
} {1 {missing value to go with key}}
test dict-4.9 {dict replace command} {dict replace [list a a] a b} {a b}
test dict-4.10 {dict replace command} {dict replace [list a a] a b a c} {a c}

test dict-5.1 {dict remove command} {dict remove {a b c d} a} {c d}
test dict-5.2 {dict remove command} {dict remove {a b c d} c} {a b}
test dict-5.3 {dict remove command} {dict remove {a b c d} a c} {}
test dict-5.4 {dict remove command} {dict remove {a b c d} c a} {}
test dict-5.5 {dict remove command} {
    getOrder [dict remove {a b c d}] a c
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
    list [catch {dict size a} msg] $msg
} {1 {missing value to go with key}}

test dict-9.1 {dict exists command} {dict exists {a b} a} 1
test dict-9.2 {dict exists command} {dict exists {a b} b} 0
test dict-9.3 {dict exists command} {dict exists {a {b c}} a b} 1
test dict-9.4 {dict exists command} {dict exists {a {b c}} a c} 0
test dict-9.5 {dict exists command} {
    list [catch {dict exists {a {b c}} b c} msg] $msg
} {1 {key "b" not known in dictionary}}
test dict-9.6 {dict exists command} {
    list [catch {dict exists {a {b c d}} a c} msg] $msg
} {1 {missing value to go with key}}
test dict-9.7 {dict exists command} {
    list [catch {dict exists} msg] $msg
} {1 {wrong # args: should be "dict exists dictionary key ?key ...?"}}
test dict-9.8 {dict exists command} {







|
<
<







200
201
202
203
204
205
206
207


208
209
210
211
212
213
214
    list [catch {dict size a} msg] $msg
} {1 {missing value to go with key}}

test dict-9.1 {dict exists command} {dict exists {a b} a} 1
test dict-9.2 {dict exists command} {dict exists {a b} b} 0
test dict-9.3 {dict exists command} {dict exists {a {b c}} a b} 1
test dict-9.4 {dict exists command} {dict exists {a {b c}} a c} 0
test dict-9.5 {dict exists command} {dict exists {a {b c}} b c} 0


test dict-9.6 {dict exists command} {
    list [catch {dict exists {a {b c d}} a c} msg] $msg
} {1 {missing value to go with key}}
test dict-9.7 {dict exists command} {
    list [catch {dict exists} msg] $msg
} {1 {wrong # args: should be "dict exists dictionary key ?key ...?"}}
test dict-9.8 {dict exists command} {
706
707
708
709
710
711
712






















































































































































713
714
715
716
717
718
719
720
} {1 {wrong # args: should be "dict filter dictionary filterType ..."}}
test dict-17.22 {dict filter command} {
    list [catch {dict filter {a b} JUNK} msg] $msg
} {1 {bad filterType "JUNK": must be key, script, or value}}
test dict-17.23 {dict filter command} {
    list [catch {dict filter a key *} msg] $msg
} {1 {missing value to go with key}}























































































































































# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:







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








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
} {1 {wrong # args: should be "dict filter dictionary filterType ..."}}
test dict-17.22 {dict filter command} {
    list [catch {dict filter {a b} JUNK} msg] $msg
} {1 {bad filterType "JUNK": must be key, script, or value}}
test dict-17.23 {dict filter command} {
    list [catch {dict filter a key *} msg] $msg
} {1 {missing value to go with key}}

test dict-18.1 {dict-list relationship} {
    -body {
        # Test that any internal conversion between list and dict
        # does not change the object
        set l [list 1 2 3 4 5 6 7 8 9 0 q w e r t y]
        dict values $l
        set l
    }
    -result {1 2 3 4 5 6 7 8 9 0 q w e r t y}
}
test dict-18.2 {dict-list relationship} {
    -body {
        # Test that the dictionary is a valid list
        set d [dict create "abc def" 0 "a\{b" 1 "c\}d" 2]
        for {set t 0} {$t < 5} {incr t} {
            llength $d
            dict lappend d "abc def" "\}\{"
            dict append  d "a\{b" "\}"
            dict incr    d "c\}d" 1
        }
        llength $d
    }
    -result 6
}

# This is a test for a specific bug.
# It shows a bad ref counter when running with memdebug on.
test dict-19.1 {memory bug} -setup {
    proc xxx {} {
        set successors [dict create x {c d}]
        dict set successors x a b
        dict get $successors x
    }
} -body {
    xxx
} -cleanup {
    rename xxx {}
} -result [dict create c d a b]
test dict-19.2 {dict: testing for leaks} -setup {
    proc getbytes {} {
        set lines [split [memory info] "\n"]
        lindex [lindex $lines 3] 3
    }
    # This test is made to stress object reference management
    proc stress {} {
        # A shared invalid dictinary
        set apa {a {}b c d}
        set bepa $apa
        catch {dict replace $apa e f}
        catch {dict remove  $apa c d}
        catch {dict incr    apa  a 5}
        catch {dict lappend apa  a 5}
        catch {dict append  apa  a 5}
        catch {dict set     apa  a 5}
        catch {dict unset   apa  a}

        # A shared valid dictionary, invalid incr
        set apa {a b c d}
        set bepa $apa
        catch {dict incr bepa a 5}

        # An error during write to an unshared object, incr
        set apa {a 1 b 2}
        set bepa [lrange $apa 0 end]
        trace add variable bepa write {error hej}
        catch {dict incr bepa a 5}
        unset bepa

        # An error during write to a shared object, incr
        set apa {a 1 b 2}
        set bepa $apa
        trace add variable bepa write {error hej}
        catch {dict incr bepa a 5}
        unset bepa

        # A shared valid dictionary, invalid lappend
        set apa [list a {{}b} c d]
        set bepa $apa
        catch {dict lappend bepa a 5}

        # An error during write to an unshared object, lappend
        set apa {a 1 b 2}
        set bepa [lrange $apa 0 end]
        trace add variable bepa write {error hej}
        catch {dict lappend bepa a 5}
        unset bepa

        # An error during write to a shared object, lappend
        set apa {a 1 b 2}
        set bepa $apa
        trace add variable bepa write {error hej}
        catch {dict lappend bepa a 5}
        unset bepa

        # An error during write to an unshared object, append
        set apa {a 1 b 2}
        set bepa [lrange $apa 0 end]
        trace add variable bepa write {error hej}
        catch {dict append bepa a 5}
        unset bepa

        # An error during write to a shared object, append
        set apa {a 1 b 2}
        set bepa $apa
        trace add variable bepa write {error hej}
        catch {dict append bepa a 5}
        unset bepa

        # An error during write to an unshared object, set
        set apa {a 1 b 2}
        set bepa [lrange $apa 0 end]
        trace add variable bepa write {error hej}
        catch {dict set bepa a 5}
        unset bepa

        # An error during write to a shared object, set
        set apa {a 1 b 2}
        set bepa $apa
        trace add variable bepa write {error hej}
        catch {dict set bepa a 5}
        unset bepa

        # An error during write to an unshared object, unset
        set apa {a 1 b 2}
        set bepa [lrange $apa 0 end]
        trace add variable bepa write {error hej}
        catch {dict unset bepa a}
        unset bepa

        # An error during write to a shared object, unset
        set apa {a 1 b 2}
        set bepa $apa
        trace add variable bepa write {error hej}
        catch {dict unset bepa a}
        unset bepa
    }
} -constraints memory -body {
    set end [getbytes]
    for {set i 0} {$i < 5} {incr i} {
        stress
        set tmp $end
        set end [getbytes]
    }
    expr {$end - $tmp}
} -cleanup {
    unset -nocomplain end i tmp
    rename getbytes {}
    rename stress {}
} -result 0

# cleanup
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:
Changes to tests/encoding.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 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.
#
# RCS: @(#) $Id: encoding.test,v 1.18 2003/03/27 21:44:05 msofer Exp $

package require tcltest 2
namespace import -force ::tcltest::*

proc toutf {args} {
    global x
    lappend x "toutf $args"










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 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.
#
# RCS: @(#) $Id: encoding.test,v 1.18.2.1 2004/02/07 05:48:02 dgp Exp $

package require tcltest 2
namespace import -force ::tcltest::*

proc toutf {args} {
    global x
    lappend x "toutf $args"
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
	    
	    # Difference should be empty.
	    set diff
	} {}
    }
}

eval [list file delete] [glob -directory [temporaryDirectory] *.chars *.tcltestout]
# ===> Cut here <===

# EscapeFreeProc, GetTableEncoding, unilen
# are fully tested by the rest of this file

# cleanup
::tcltest::cleanupTests
return







|








537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
	    
	    # Difference should be empty.
	    set diff
	} {}
    }
}

file delete {expand}[glob -directory [temporaryDirectory] *.chars *.tcltestout]
# ===> Cut here <===

# EscapeFreeProc, GetTableEncoding, unilen
# are fully tested by the rest of this file

# cleanup
::tcltest::cleanupTests
return
Changes to tests/execute.test.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#
# 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.
#
# RCS: @(#) $Id: execute.test,v 1.13.4.1 2003/10/16 02:28:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

catch {eval namespace delete [namespace children :: test_ns_*]}
catch {rename foo ""}
catch {unset x}
catch {unset y}
catch {unset msg}

::tcltest::testConstraint testobj \
	[expr {[info commands testobj] != {} \







|






|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#
# 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.
#
# RCS: @(#) $Id: execute.test,v 1.13.4.2 2004/02/07 05:48:02 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

catch {namespace delete {expand}[namespace children :: test_ns_*]}
catch {rename foo ""}
catch {unset x}
catch {unset y}
catch {unset msg}

::tcltest::testConstraint testobj \
	[expr {[info commands testobj] != {} \
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
# INST_FOREACH_STEP4 not tested
# INST_BEGIN_CATCH4 not tested
# INST_END_CATCH not tested
# INST_PUSH_RESULT not tested
# INST_PUSH_RETURN_CODE not tested

test execute-4.1 {Tcl_GetCommandFromObj, convert to tclCmdNameType} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {unset x}
    catch {unset y}
    namespace eval test_ns_1 {
        namespace export cmd1
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_1::test_ns_2 {
        namespace import ::test_ns_1::*
    }
    set x "test_ns_1::"
    set y "test_ns_2::"
    list [namespace which -command ${x}${y}cmd1] \
         [catch {namespace which -command ${x}${y}cmd2} msg] $msg \
         [catch {namespace which -command ${x}${y}:cmd2} msg] $msg
} {::test_ns_1::test_ns_2::cmd1 0 {} 0 {}}
test execute-4.2 {Tcl_GetCommandFromObj, check if cached tclCmdNameType is invalid} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {rename foo ""}
    catch {unset l}
    proc foo {} {
        return "global foo"
    }
    namespace eval test_ns_1 {
        proc whichFoo {} {







|

















|







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
# INST_FOREACH_STEP4 not tested
# INST_BEGIN_CATCH4 not tested
# INST_END_CATCH not tested
# INST_PUSH_RESULT not tested
# INST_PUSH_RETURN_CODE not tested

test execute-4.1 {Tcl_GetCommandFromObj, convert to tclCmdNameType} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {unset x}
    catch {unset y}
    namespace eval test_ns_1 {
        namespace export cmd1
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_1::test_ns_2 {
        namespace import ::test_ns_1::*
    }
    set x "test_ns_1::"
    set y "test_ns_2::"
    list [namespace which -command ${x}${y}cmd1] \
         [catch {namespace which -command ${x}${y}cmd2} msg] $msg \
         [catch {namespace which -command ${x}${y}:cmd2} msg] $msg
} {::test_ns_1::test_ns_2::cmd1 0 {} 0 {}}
test execute-4.2 {Tcl_GetCommandFromObj, check if cached tclCmdNameType is invalid} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {rename foo ""}
    catch {unset l}
    proc foo {} {
        return "global foo"
    }
    namespace eval test_ns_1 {
        proc whichFoo {} {
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
            return "namespace foo"
        }
    }
    lappend l [test_ns_1::whichFoo]
    set l
} {::foo ::test_ns_1::foo}
test execute-4.3 {Tcl_GetCommandFromObj, command never found} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {rename foo ""}
    namespace eval test_ns_1 {
        proc foo {} {
            return "namespace foo"
        }
    }
    namespace eval test_ns_1 {
        proc foo {} {
            return "namespace foo"
        }
    }
    list [namespace eval test_ns_1 {namespace which -command foo}] \
         [rename test_ns_1::foo ""] \
         [catch {namespace eval test_ns_1 {namespace which -command foo}} msg] $msg
} {::test_ns_1::foo {} 0 {}}

test execute-5.1 {SetCmdNameFromAny, set cmd name to empty heap string if NULL} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {unset l}
    proc {} {} {return {}}
    {}
    set l {}
    lindex {} 0
    {}
} {}







|

















|







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
            return "namespace foo"
        }
    }
    lappend l [test_ns_1::whichFoo]
    set l
} {::foo ::test_ns_1::foo}
test execute-4.3 {Tcl_GetCommandFromObj, command never found} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {rename foo ""}
    namespace eval test_ns_1 {
        proc foo {} {
            return "namespace foo"
        }
    }
    namespace eval test_ns_1 {
        proc foo {} {
            return "namespace foo"
        }
    }
    list [namespace eval test_ns_1 {namespace which -command foo}] \
         [rename test_ns_1::foo ""] \
         [catch {namespace eval test_ns_1 {namespace which -command foo}} msg] $msg
} {::test_ns_1::foo {} 0 {}}

test execute-5.1 {SetCmdNameFromAny, set cmd name to empty heap string if NULL} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {unset l}
    proc {} {} {return {}}
    {}
    set l {}
    lindex {} 0
    {}
} {}
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
 } {too many nested evaluations (infinite loop?)}


# cleanup
if {[info commands testobj] != {}} {
   testobj freeallvars
}
catch {eval namespace delete [namespace children :: test_ns_*]}
catch {rename foo ""}
catch {rename p ""}
catch {rename {} ""}
catch {rename { } ""}
catch {unset x}
catch {unset y}
catch {unset msg}
::tcltest::cleanupTests
return







|









730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
 } {too many nested evaluations (infinite loop?)}


# cleanup
if {[info commands testobj] != {}} {
   testobj freeallvars
}
catch {namespace delete {expand}[namespace children :: test_ns_*]}
catch {rename foo ""}
catch {rename p ""}
catch {rename {} ""}
catch {rename { } ""}
catch {unset x}
catch {unset y}
catch {unset msg}
::tcltest::cleanupTests
return
Changes to tests/fCmd.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# This file tests the tclFCmd.c file.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1996-1997 Sun Microsystems, Inc.
# Copyright (c) 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.
#
# RCS: @(#) $Id: fCmd.test,v 1.27.2.3 2003/10/16 02:28:03 dgp Exp $
#

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# This file tests the tclFCmd.c file.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1996-1997 Sun Microsystems, Inc.
# Copyright (c) 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.
#
# RCS: @(#) $Id: fCmd.test,v 1.27.2.4 2004/02/07 05:48:02 dgp Exp $
#

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

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
    file mkdir td2
    list [catch {file rename -force td2 td1} msg] $msg
} [subst {1 {error renaming "td2" to "[file join td1 td2]": file already exists}}]
test fCmd-6.19 {CopyRenameOneFile: errno == EXDEV} {unixOnly notRoot} {
    cleanup /tmp
    createfile tf1
    file rename tf1 /tmp
    glob tf* /tmp/tf1
} {/tmp/tf1}
test fCmd-6.20 {CopyRenameOneFile: errno == EXDEV} {pcOnly} {
    catch {file delete -force c:/tcl8975@ d:/tcl8975@}
    file mkdir c:/tcl8975@
    if [catch {file rename c:/tcl8975@ d:/}] {
	set msg d:/tcl8975@
    } else {
	set msg [glob c:/tcl8975@ d:/tcl8975@]
	file delete -force d:/tcl8975@
    }
    file delete -force c:/tcl8975@
    set msg
} {d:/tcl8975@}
test fCmd-6.21 {CopyRenameOneFile: copy/rename: S_ISDIR(source)} \
	{unixOnly notRoot} {
    cleanup /tmp
    file mkdir td1
    file rename td1 /tmp
    glob td* /tmp/td*
} {/tmp/td1}
test fCmd-6.22 {CopyRenameOneFile: copy/rename: !S_ISDIR(source)} \
	{unixOnly notRoot} {
    cleanup /tmp
    createfile tf1
    file rename tf1 /tmp
    glob tf* /tmp/tf*
} {/tmp/tf1}
test fCmd-6.23 {CopyRenameOneFile: TclpCopyDirectory failed} \
	{unixOnly notRoot xdev} {
    cleanup /tmp
    file mkdir td1/td2/td3
    file attributes td1 -permissions 0000
    set msg [list [catch {file rename td1 /tmp} msg] $msg]







|


















|






|







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
    file mkdir td2
    list [catch {file rename -force td2 td1} msg] $msg
} [subst {1 {error renaming "td2" to "[file join td1 td2]": file already exists}}]
test fCmd-6.19 {CopyRenameOneFile: errno == EXDEV} {unixOnly notRoot} {
    cleanup /tmp
    createfile tf1
    file rename tf1 /tmp
    glob -nocomplain tf* /tmp/tf1
} {/tmp/tf1}
test fCmd-6.20 {CopyRenameOneFile: errno == EXDEV} {pcOnly} {
    catch {file delete -force c:/tcl8975@ d:/tcl8975@}
    file mkdir c:/tcl8975@
    if [catch {file rename c:/tcl8975@ d:/}] {
	set msg d:/tcl8975@
    } else {
	set msg [glob c:/tcl8975@ d:/tcl8975@]
	file delete -force d:/tcl8975@
    }
    file delete -force c:/tcl8975@
    set msg
} {d:/tcl8975@}
test fCmd-6.21 {CopyRenameOneFile: copy/rename: S_ISDIR(source)} \
	{unixOnly notRoot} {
    cleanup /tmp
    file mkdir td1
    file rename td1 /tmp
    glob -nocomplain td* /tmp/td*
} {/tmp/td1}
test fCmd-6.22 {CopyRenameOneFile: copy/rename: !S_ISDIR(source)} \
	{unixOnly notRoot} {
    cleanup /tmp
    createfile tf1
    file rename tf1 /tmp
    glob -nocomplain tf* /tmp/tf*
} {/tmp/tf1}
test fCmd-6.23 {CopyRenameOneFile: TclpCopyDirectory failed} \
	{unixOnly notRoot xdev} {
    cleanup /tmp
    file mkdir td1/td2/td3
    file attributes td1 -permissions 0000
    set msg [list [catch {file rename td1 /tmp} msg] $msg]
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
test fCmd-9.14.1 {file rename: comprehensive: dir into self} {notRoot} {
    cleanup
    file mkdir td1
    file rename td1 td1x
    file rename td1x td1
    set msg "ok"
} {ok}
test fCmd-9.14.2 {file rename: comprehensive: dir into self} {notRoot} {
    cleanup
    file mkdir td1
    set dir [pwd]
    cd td1
    set res [list [catch {file rename [file join .. td1] [file join .. td1x]} msg] $msg]
    cd $dir
    set res







|







865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
test fCmd-9.14.1 {file rename: comprehensive: dir into self} {notRoot} {
    cleanup
    file mkdir td1
    file rename td1 td1x
    file rename td1x td1
    set msg "ok"
} {ok}
test fCmd-9.14.2 {file rename: comprehensive: dir into self} {nonPortable notRoot} {
    cleanup
    file mkdir td1
    set dir [pwd]
    cd td1
    set res [list [catch {file rename [file join .. td1] [file join .. td1x]} msg] $msg]
    cd $dir
    set res
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
} {1}

test fCmd-26.2 {TclDeleteFilesCmd: delete dir with symlink} {unixOnly notRoot} {
    catch {file delete -force -- tfad1 tfad2}
		
    file mkdir tfad1
    file mkdir tfad2
    file link -symbolic [file join tfad2 link] tfad1
    file delete -force tfad2

    set r1 [file isdir tfad1]
    set r2 [file exists tfad2]
    
    set result [expr $r1 && !$r2]
    file delete tfad1







|







2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
} {1}

test fCmd-26.2 {TclDeleteFilesCmd: delete dir with symlink} {unixOnly notRoot} {
    catch {file delete -force -- tfad1 tfad2}
		
    file mkdir tfad1
    file mkdir tfad2
    file link -symbolic [file join tfad2 link] [file join .. tfad1]
    file delete -force tfad2

    set r1 [file isdir tfad1]
    set r2 [file exists tfad2]
    
    set result [expr $r1 && !$r2]
    file delete tfad1
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
    createfile foo.tmp
    list [catch {file attributes foo.tmp} msg] [expr {[llength $msg] > 0}] [file delete -force -- foo.tmp]
} {0 1 {}}
test fCmd-27.4 {TclFileAttrsCmd - getting one option} {
    catch {file delete -force -- foo.tmp}
    createfile foo.tmp
    set attrs [file attributes foo.tmp]
    list [catch {eval file attributes foo.tmp [lindex $attrs 0]}] [file delete -force -- foo.tmp]
} {0 {}}

# Find a group that exists on this Unix system, or else skip tests that
# require Unix groups.
if {$tcl_platform(platform) == "unix"} {
    ::tcltest::testConstraint foundGroup 0
    catch {
	set groupList [exec groups]
	set group [lindex $groupList 0]
	::tcltest::testConstraint foundGroup 1
    }
} else {
    ::tcltest::testConstraint foundGroup 1
}

test fCmd-27.5 {TclFileAttrsCmd - setting one option} {foundGroup} {
    catch {file delete -force -- foo.tmp}
    createfile foo.tmp
    set attrs [file attributes foo.tmp]
    list [catch {eval file attributes foo.tmp [lrange $attrs 0 1]} msg] $msg [file delete -force -- foo.tmp]
} {0 {} {}}
test fCmd-27.6 {TclFileAttrsCmd - setting more than one option} {foundGroup} {
    catch {file delete -force -- foo.tmp}
    createfile foo.tmp
    set attrs [file attributes foo.tmp]
    list [catch {eval file attributes foo.tmp [lrange $attrs 0 3]} msg] $msg [file delete -force -- foo.tmp]
} {0 {} {}}

if {[string equal $tcl_platform(platform) "windows"]} {
    if {[string index $tcl_platform(osVersion) 0] >= 5 \
      && ([lindex [file system [temporaryDirectory]] 1] == "NTFS")} {
	tcltest::testConstraint linkDirectory 1
	tcltest::testConstraint linkFile 1







|



















|





|







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
    createfile foo.tmp
    list [catch {file attributes foo.tmp} msg] [expr {[llength $msg] > 0}] [file delete -force -- foo.tmp]
} {0 1 {}}
test fCmd-27.4 {TclFileAttrsCmd - getting one option} {
    catch {file delete -force -- foo.tmp}
    createfile foo.tmp
    set attrs [file attributes foo.tmp]
    list [catch {file attributes foo.tmp {expand}[lindex $attrs 0]}] [file delete -force -- foo.tmp]
} {0 {}}

# Find a group that exists on this Unix system, or else skip tests that
# require Unix groups.
if {$tcl_platform(platform) == "unix"} {
    ::tcltest::testConstraint foundGroup 0
    catch {
	set groupList [exec groups]
	set group [lindex $groupList 0]
	::tcltest::testConstraint foundGroup 1
    }
} else {
    ::tcltest::testConstraint foundGroup 1
}

test fCmd-27.5 {TclFileAttrsCmd - setting one option} {foundGroup} {
    catch {file delete -force -- foo.tmp}
    createfile foo.tmp
    set attrs [file attributes foo.tmp]
    list [catch {file attributes foo.tmp {expand}[lrange $attrs 0 1]} msg] $msg [file delete -force -- foo.tmp]
} {0 {} {}}
test fCmd-27.6 {TclFileAttrsCmd - setting more than one option} {foundGroup} {
    catch {file delete -force -- foo.tmp}
    createfile foo.tmp
    set attrs [file attributes foo.tmp]
    list [catch {file attributes foo.tmp {expand}[lrange $attrs 0 3]} msg] $msg [file delete -force -- foo.tmp]
} {0 {} {}}

if {[string equal $tcl_platform(platform) "windows"]} {
    if {[string index $tcl_platform(osVersion) 0] >= 5 \
      && ([lindex [file system [temporaryDirectory]] 1] == "NTFS")} {
	tcltest::testConstraint linkDirectory 1
	tcltest::testConstraint linkFile 1
2302
2303
2304
2305
2306
2307
2308
2309








2310
2311
2312
2313
2314
2315
2316

test fCmd-28.10 {file link: linking to nonexistent path} {linkDirectory} {
    cd [temporaryDirectory]
    file delete -force abc.link
    set res [list [catch {file link abc.link abc2.doesnt} msg] $msg]
    cd [workingDirectory]
    set res
} {1 {could not create new link "abc.link" since target "abc2.doesnt" doesn't exist}}









test fCmd-28.11 {file link: success with directory} {linkDirectory} {
    cd [temporaryDirectory]
    file delete -force abc.link
    set res [list [catch {file link abc.link abc.dir} msg] $msg]
    cd [workingDirectory]
    set res







|
>
>
>
>
>
>
>
>







2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324

test fCmd-28.10 {file link: linking to nonexistent path} {linkDirectory} {
    cd [temporaryDirectory]
    file delete -force abc.link
    set res [list [catch {file link abc.link abc2.doesnt} msg] $msg]
    cd [workingDirectory]
    set res
} {1 {could not create new link "abc.link": target "abc2.doesnt" doesn't exist}}

test fCmd-28.10.1 {file link: linking to nonexistent path} {linkDirectory} {
    cd [temporaryDirectory]
    file delete -force abc.link
    set res [list [catch {file link doesnt/abc.link abc.dir} msg] $msg]
    cd [workingDirectory]
    set res
} {1 {could not create new link "doesnt/abc.link": no such file or directory}}

test fCmd-28.11 {file link: success with directory} {linkDirectory} {
    cd [temporaryDirectory]
    file delete -force abc.link
    set res [list [catch {file link abc.link abc.dir} msg] $msg]
    cd [workingDirectory]
    set res
2328
2329
2330
2331
2332
2333
2334
2335


2336
2337
2338
2339
2340
2341
2342
    cd $orig
    # now '$up' should be either $orig or [file dirname abc.dir],
    # depending on whether 'cd' actually moves to the destination
    # of a link, or simply treats the link as a directory.
    # (on windows the former, on unix the latter, I believe)
    if {([file normalize $up] != [file normalize $orig]) \
      && ([file normalize $up] != [file normalize [file dirname abc.dir]])} {
	set res "wrong directory with 'cd $link ; cd ..'"


    } else {
	set res "ok"
    }
    cd [workingDirectory]
    set res
} {ok}








|
>
>







2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
    cd $orig
    # now '$up' should be either $orig or [file dirname abc.dir],
    # depending on whether 'cd' actually moves to the destination
    # of a link, or simply treats the link as a directory.
    # (on windows the former, on unix the latter, I believe)
    if {([file normalize $up] != [file normalize $orig]) \
      && ([file normalize $up] != [file normalize [file dirname abc.dir]])} {
	set res "wrong directory with 'cd abc.link ; cd ..': \
	  \"[file normalize $up]\" should be \"[file normalize $orig]\" or\
	  \"[file normalize [file dirname abc.dir]]\""
    } else {
	set res "ok"
    }
    cd [workingDirectory]
    set res
} {ok}

2376
2377
2378
2379
2380
2381
2382
2383



2384
2385
2386
2387
2388
2389
2390
    cd [workingDirectory]
    set res
} {link abc.dir}

cd [temporaryDirectory]
file delete -force abc.link
file delete -force abc2.link




file copy abc.file abc.dir
file copy abc2.file abc.dir
cd [workingDirectory]

test fCmd-28.16 {file link: glob inside link} {linkDirectory} {
    cd [temporaryDirectory]
    file delete -force abc.link







|
>
>
>







2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
    cd [workingDirectory]
    set res
} {link abc.dir}

cd [temporaryDirectory]
file delete -force abc.link
file delete -force abc2.link
cd abc.dir
file delete -force abc.file
file delete -force abc2.file
cd ..
file copy abc.file abc.dir
file copy abc2.file abc.dir
cd [workingDirectory]

test fCmd-28.16 {file link: glob inside link} {linkDirectory} {
    cd [temporaryDirectory]
    file delete -force abc.link
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

test fCmd-28.18 {file link: glob -type d} {linkDirectory} {
    cd [temporaryDirectory]
    set res [lsort [glob -dir [pwd] -type d -tails abc*]]
    cd [workingDirectory]
    set res
} [lsort [list abc.link abc.dir abc2.dir]]



























test fCmd-29.1 {weird memory corruption fault} {
    catch {set res [open [file join ~a_totally_bogus_user_id/foo bar]]}
} 1

cd [temporaryDirectory]
file delete -force abc.link


cd [workingDirectory]

removeFile abc2.file
removeFile abc.file
removeDirectory abc2.dir
removeDirectory abc.dir

# cleanup
cleanup
::tcltest::cleanupTests
return







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







>
>











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

test fCmd-28.18 {file link: glob -type d} {linkDirectory} {
    cd [temporaryDirectory]
    set res [lsort [glob -dir [pwd] -type d -tails abc*]]
    cd [workingDirectory]
    set res
} [lsort [list abc.link abc.dir abc2.dir]]

test fCmd-28.19 {file link: relative paths} {winOnly linkDirectory} {
    cd [temporaryDirectory]
    file mkdir d1/d2/d3
    set res [list [catch {file link d1/l2 d1/d2} err] $err]
    lappend res [catch {file delete -force d1} err] $err
} {0 d1/d2 0 {}}

test fCmd-28.20 {file link: relative paths} {unixOnly linkDirectory} {
    cd [temporaryDirectory]
    file mkdir d1/d2/d3
    list [catch {file link d1/l2 d1/d2} res] $res
} {1 {could not create new link "d1/l2": target "d1/d2" doesn't exist}}

test fCmd-28.21 {file link: relative paths} {unixOnly linkDirectory} {
    cd [temporaryDirectory]
    file mkdir d1/d2/d3
    list [catch {file link d1/l2 d2} res] $res
} {0 d2}

test fCmd-28.22 {file link: relative paths} {unixOnly linkDirectory} {
    cd [temporaryDirectory]
    file mkdir d1/d2/d3
    catch {file delete -force d1/l2}
    list [catch {file link d1/l2 d2/d3} res] $res
} {0 d2/d3}

test fCmd-29.1 {weird memory corruption fault} {
    catch {set res [open [file join ~a_totally_bogus_user_id/foo bar]]}
} 1

cd [temporaryDirectory]
file delete -force abc.link
file delete -force d1/d2
file delete -force d1
cd [workingDirectory]

removeFile abc2.file
removeFile abc.file
removeDirectory abc2.dir
removeDirectory abc.dir

# cleanup
cleanup
::tcltest::cleanupTests
return
Changes to tests/fileName.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# This file tests the filename manipulation routines.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1995-1996 Sun Microsystems, Inc.
# Copyright (c) 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.
#
# RCS: @(#) $Id: fileName.test,v 1.31.2.1 2003/10/16 02:28:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

tcltest::testConstraint testsetplatform [string equal testsetplatform [info commands testsetplatform]]












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# This file tests the filename manipulation routines.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1995-1996 Sun Microsystems, Inc.
# Copyright (c) 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.
#
# RCS: @(#) $Id: fileName.test,v 1.31.2.2 2004/02/07 05:48:02 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

tcltest::testConstraint testsetplatform [string equal testsetplatform [info commands testsetplatform]]
997
998
999
1000
1001
1002
1003




1004
1005
1006
1007
1008
1009
1010
    testsetplatform windows
    list [catch {testtranslatefilename {c:/foo}} msg] $msg
} {0 {c:\foo}}
test filename-10.3 {Tcl_TranslateFileName} {testsetplatform} {
    testsetplatform windows
    list [catch {testtranslatefilename {c:/\\foo/}} msg] $msg
} {0 {c:\foo}}




test filename-10.4 {Tcl_TranslateFileName} {testsetplatform} {
    testsetplatform mac
    list [catch {testtranslatefilename foo} msg] $msg
} {0 :foo}
test filename-10.5 {Tcl_TranslateFileName} {testsetplatform} {
    testsetplatform mac
    list [catch {testtranslatefilename :~foo} msg] $msg







>
>
>
>







997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
    testsetplatform windows
    list [catch {testtranslatefilename {c:/foo}} msg] $msg
} {0 {c:\foo}}
test filename-10.3 {Tcl_TranslateFileName} {testsetplatform} {
    testsetplatform windows
    list [catch {testtranslatefilename {c:/\\foo/}} msg] $msg
} {0 {c:\foo}}
test filename-10.3.1 {Tcl_TranslateFileName} {testsetplatform} {
    testsetplatform windows
    list [catch {testtranslatefilename {c://///}} msg] $msg
} {0 c:\\}
test filename-10.4 {Tcl_TranslateFileName} {testsetplatform} {
    testsetplatform mac
    list [catch {testtranslatefilename foo} msg] $msg
} {0 :foo}
test filename-10.5 {Tcl_TranslateFileName} {testsetplatform} {
    testsetplatform mac
    list [catch {testtranslatefilename :~foo} msg] $msg
1580
1581
1582
1583
1584
1585
1586
1587




1588
1589
1590
1591
1592
1593
1594
    }
    catch {
	set tmpd [pwd]
	cd [lindex [file volumes] 0]
	set res2 [glob *]
	cd $tmpd
    }
    expr {$res1 == $res2}




} {1}
test filename-11.46 {Tcl_GlobCmd} {
    list [catch {glob -types abcde -dir foo *} msg] $msg
} {1 {bad argument to "-types": abcde}}
test filename-11.47 {Tcl_GlobCmd} {
    list [catch {glob -types abcde -path foo *} msg] $msg
} {1 {bad argument to "-types": abcde}}







|
>
>
>
>







1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
    }
    catch {
	set tmpd [pwd]
	cd [lindex [file volumes] 0]
	set res2 [glob *]
	cd $tmpd
    }
    set res [expr {$res1 == $res2}]
    if {!$res} {
	lappend res $res1 $res2
    }
    set res
} {1}
test filename-11.46 {Tcl_GlobCmd} {
    list [catch {glob -types abcde -dir foo *} msg] $msg
} {1 {bad argument to "-types": abcde}}
test filename-11.47 {Tcl_GlobCmd} {
    list [catch {glob -types abcde -path foo *} msg] $msg
} {1 {bad argument to "-types": abcde}}
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
    # is reset... 
    string equal [glob -nocomplain ~wontexist ~blah ~] \
      [glob -nocomplain ~ ~blah ~wontexist]
} {1}
test filename-15.5 {unix specific globbing} {unixOnly nonPortable} {
    glob ~ouster/.csh*
} "/home/ouster/.cshrc"
catch {close [open globTest/odd\\\[\]*?\{\}name w]}
test filename-15.6 {unix specific globbing} {unixOnly} {
    global env
    set temp $env(HOME)
    set env(HOME) $env(HOME)/globTest/odd\\\[\]*?\{\}name
    set result [list [catch {glob ~} msg] $msg]
    set env(HOME) $temp
    set result
} [list 0 [list [lindex [glob ~] 0]/globTest/odd\\\[\]*?\{\}name]]
catch {file delete -force globTest/odd\\\[\]*?\{\}name}


















# The following tests are only valid for Windows systems.
set oldDir [pwd]
if {$::tcltest::testConstraints(pcOnly)} {
    cd c:/
    file delete -force globTest
    file mkdir globTest
    close [open globTest/x1.BAT w]
    close [open globTest/y1.Bat w]
    close [open globTest/z1.bat w]
}

test filename-16.1 {windows specific globbing} {pcOnly} {
    lsort [glob globTest/*.bat]
} {globTest/x1.BAT globTest/y1.Bat globTest/z1.bat}
test filename-16.2 {windows specific globbing} {pcOnly} {

    glob c:






} c:
test filename-16.3 {windows specific globbing} {pcOnly} {
    glob c:\\\\
} c:/
test filename-16.4 {windows specific globbing} {pcOnly} {
    glob c:/
} c:/
test filename-16.5 {windows specific globbing} {pcOnly} {
    glob c:*bTest
} c:globTest
test filename-16.6 {windows specific globbing} {pcOnly} {
    glob c:\\\\*bTest
} c:/globTest
test filename-16.7 {windows specific globbing} {pcOnly} {
    glob c:/*bTest
} c:/globTest
test filename-16.8 {windows specific globbing} {pcOnly} {
    lsort [glob c:globTest/*.bat]
} {c:globTest/x1.BAT c:globTest/y1.Bat c:globTest/z1.bat}
test filename-16.9 {windows specific globbing} {pcOnly} {
    lsort [glob c:/globTest/*.bat]
} {c:/globTest/x1.BAT c:/globTest/y1.Bat c:/globTest/z1.bat}
test filename-16.10 {windows specific globbing} {pcOnly} {
    lsort [glob c:globTest\\\\*.bat]
} {c:globTest/x1.BAT c:globTest/y1.Bat c:globTest/z1.bat}
test filename-16.11 {windows specific globbing} {pcOnly} {
    lsort [glob c:\\\\globTest\\\\*.bat]
} {c:/globTest/x1.BAT c:/globTest/y1.Bat c:/globTest/z1.bat}

# some tests require a shared C drive

if {[catch {cd //[info hostname]/c}]} {
    set ::tcltest::testConstraints(sharedCdrive) 0
} else {







|









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
















>
|
>
>
>
>
>
>
|

|


|


|


|


|


|


|


|


|







1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
    # is reset... 
    string equal [glob -nocomplain ~wontexist ~blah ~] \
      [glob -nocomplain ~ ~blah ~wontexist]
} {1}
test filename-15.5 {unix specific globbing} {unixOnly nonPortable} {
    glob ~ouster/.csh*
} "/home/ouster/.cshrc"
catch {close [open globTest/odd\\\[\]*?\{\}name w]} 
test filename-15.6 {unix specific globbing} {unixOnly} {
    global env
    set temp $env(HOME)
    set env(HOME) $env(HOME)/globTest/odd\\\[\]*?\{\}name
    set result [list [catch {glob ~} msg] $msg]
    set env(HOME) $temp
    set result
} [list 0 [list [lindex [glob ~] 0]/globTest/odd\\\[\]*?\{\}name]]
catch {file delete -force globTest/odd\\\[\]*?\{\}name}
test filename-15.7 {win specific globbing} {winOnly} {
    if {[string index [glob ~] end] == "/"} {
	set res "glob ~ is [glob ~] but shouldn't end in a separator"
    } else {
	set res "ok"
    }
} {ok}
test filename-15.8 {win and unix specific globbing} {unixOrWin} {
    global env
    set temp $env(HOME)
    catch {close [open $env(HOME)/globTest/anyname w]} err
    set env(HOME) $env(HOME)/globTest/anyname
    set result [list [catch {glob ~} msg] $msg]
    set env(HOME) $temp
    catch {file delete -force $env(HOME)/globTest/anyname}
    set result
} [list 0 [list [lindex [glob ~] 0]/globTest/anyname]]

# The following tests are only valid for Windows systems.
set oldDir [pwd]
if {$::tcltest::testConstraints(pcOnly)} {
    cd c:/
    file delete -force globTest
    file mkdir globTest
    close [open globTest/x1.BAT w]
    close [open globTest/y1.Bat w]
    close [open globTest/z1.bat w]
}

test filename-16.1 {windows specific globbing} {pcOnly} {
    lsort [glob globTest/*.bat]
} {globTest/x1.BAT globTest/y1.Bat globTest/z1.bat}
test filename-16.2 {windows specific globbing} {pcOnly} {
    list [catch {glob c:} res] $res
} {0 c:}
test filename-16.2.1 {windows specific globbing} {pcOnly} {
    set dir [pwd]
    cd C:/
    set res [list [catch {glob c:} err] $err]
    cd $dir
    set res
} {0 c:}
test filename-16.3 {windows specific globbing} {pcOnly} {
    glob -nocomplain c:\\\\
} c:/
test filename-16.4 {windows specific globbing} {pcOnly} {
    glob -nocomplain c:/
} c:/
test filename-16.5 {windows specific globbing} {pcOnly} {
    glob -nocomplain c:*bTest
} c:globTest
test filename-16.6 {windows specific globbing} {pcOnly} {
    glob -nocomplain c:\\\\*bTest
} c:/globTest
test filename-16.7 {windows specific globbing} {pcOnly} {
    glob -nocomplain c:/*bTest
} c:/globTest
test filename-16.8 {windows specific globbing} {pcOnly} {
    lsort [glob -nocomplain c:globTest/*.bat]
} {c:globTest/x1.BAT c:globTest/y1.Bat c:globTest/z1.bat}
test filename-16.9 {windows specific globbing} {pcOnly} {
    lsort [glob -nocomplain c:/globTest/*.bat]
} {c:/globTest/x1.BAT c:/globTest/y1.Bat c:/globTest/z1.bat}
test filename-16.10 {windows specific globbing} {pcOnly} {
    lsort [glob -nocomplain c:globTest\\\\*.bat]
} {c:globTest/x1.BAT c:globTest/y1.Bat c:globTest/z1.bat}
test filename-16.11 {windows specific globbing} {pcOnly} {
    lsort [glob -nocomplain c:\\\\globTest\\\\*.bat]
} {c:/globTest/x1.BAT c:/globTest/y1.Bat c:/globTest/z1.bat}

# some tests require a shared C drive

if {[catch {cd //[info hostname]/c}]} {
    set ::tcltest::testConstraints(sharedCdrive) 0
} else {
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
    expr {[lsearch -exact [glob {{.,*}*}] ".."] != -1}
} {1}
test filename-16.15 {windows specific globbing} {pcOnly} {
    cd [lindex [glob -types d -dir C:/ *] 0]
    glob ..
} {..}
test filename-16.16 {windows specific globbing} {pcOnly} {
    file tail [lindex [glob "[lindex [glob -types d -dir C:/ *] 0]/.."] 0]
} {..}

test filename-17.1 {windows specific special files} {testsetplatform} {
    testsetplatform win
    list [file pathtype com1] [file pathtype con] [file pathtype lpt3] \
      [file pathtype prn] [file pathtype nul] [file pathtype aux] \
      [file pathtype foo]







|







1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
    expr {[lsearch -exact [glob {{.,*}*}] ".."] != -1}
} {1}
test filename-16.15 {windows specific globbing} {pcOnly} {
    cd [lindex [glob -types d -dir C:/ *] 0]
    glob ..
} {..}
test filename-16.16 {windows specific globbing} {pcOnly} {
    file tail [lindex [glob -nocomplain "[lindex [glob -types d -dir C:/ *] 0]/.."] 0]
} {..}

test filename-17.1 {windows specific special files} {testsetplatform} {
    testsetplatform win
    list [file pathtype com1] [file pathtype con] [file pathtype lpt3] \
      [file pathtype prn] [file pathtype nul] [file pathtype aux] \
      [file pathtype foo]
Changes to tests/fileSystem.test.
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
	namespace import ::tcltest::removeFile
	namespace import ::tcltest::test
    }
    
    catch {
	file delete -force link.file
	file delete -force dir.link
	file delete -force [file join dir.file linkinside.file]
    }

makeFile "test file" gorp.file
makeDirectory dir.file

makeFile "test file in directory" [file join dir.file inside.file]









if {[catch {
    file link link.file gorp.file 

    file link \
      [file join dir.file linkinside.file] \
      [file join dir.file inside.file]

    file link dir.link dir.file




}]} {
    tcltest::testConstraint hasLinks 0
} else {
    tcltest::testConstraint hasLinks 1
}






tcltest::testConstraint testsimplefilesystem \
  [string equal testsimplefilesystem [info commands testsimplefilesystem]]

test filesystem-1.0 {link normalisation} {hasLinks} {
   string equal [file normalize gorp.file] [file normalize link.file]
} {0}

test filesystem-1.1 {link normalisation} {hasLinks} {
   string equal [file normalize dir.file] [file normalize dir.link]
} {0}

test filesystem-1.2 {link normalisation} {hasLinks macOrUnix} {
   string equal [file normalize [file join gorp.file foo]] \
     [file normalize [file join link.file foo]]
} {1}

test filesystem-1.3 {link normalisation} {hasLinks} {
   string equal [file normalize [file join dir.file foo]] \
     [file normalize [file join dir.link foo]]
} {1}

test filesystem-1.4 {link normalisation} {hasLinks} {
   string equal [file normalize [file join dir.file inside.file]] \
     [file normalize [file join dir.link inside.file]]
} {1}

test filesystem-1.5 {link normalisation} {hasLinks} {
   string equal [file normalize [file join dir.file linkinside.file]] \
     [file normalize [file join dir.file linkinside.file]]
} {1}

test filesystem-1.6 {link normalisation} {hasLinks} {
   string equal [file normalize [file join dir.file linkinside.file]] \
     [file normalize [file join dir.link inside.file]]
} {0}

test filesystem-1.7 {link normalisation} {hasLinks macOrUnix} {
   string equal [file normalize [file join dir.link linkinside.file foo]] \
     [file normalize [file join dir.file inside.file foo]]
} {1}

test filesystem-1.8 {link normalisation} {hasLinks} {
   string equal [file normalize [file join dir.file linkinside.filefoo]] \
     [file normalize [file join dir.link inside.filefoo]]
} {0}

test filesystem-1.9 {link normalisation} {macOrUnix hasLinks} {
    file delete -force dir.link
    file link dir.link [file nativename dir.file]
    string equal [file normalize [file join dir.file linkinside.file foo]] \
      [file normalize [file join dir.link inside.file foo]]
} {1}

test filesystem-1.10 {link normalisation: double link} {macOrUnix hasLinks} {
    file link dir2.link dir.link
    string equal [file normalize [file join dir.file 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} {macOrUnix hasLinks} {
    file link [file join dir2.file dir2.link] dir2.link
    string equal [file normalize [file join dir.file 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}







|



|
>
|

>
>
>
>
>
>
>
>

|
>

|
|
>
|
>
>
>
>





>
>
>
>
>









|



|




|




|




|
|



|




|
|



|





|
|





|






|
|







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
	namespace import ::tcltest::removeFile
	namespace import ::tcltest::test
    }
    
    catch {
	file delete -force link.file
	file delete -force dir.link
	file delete -force [file join dir.dir linkinside.file]
    }

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]

proc testPathEqual {one two} {
    if {[string equal $one $two]} {
	return 1
    } else {
	return "not equal: $one $two"
    }
}

if {[catch {
    file link link.file gorp.file
    cd dir.dir
    file link \
      [file join linkinside.file] \
      [file join inside.file]
    cd ..
    file link dir.link dir.dir
    cd dir.dir
    file link [file join dirinside.link] \
      [file join dirinside.dir]
    cd ..
}]} {
    tcltest::testConstraint hasLinks 0
} else {
    tcltest::testConstraint hasLinks 1
}

tcltest::testConstraint testsetplatform [string equal testsetplatform [info commands testsetplatform]]
if {[tcltest::testConstraint testsetplatform]} {
    set platform [testgetplatform]
}

tcltest::testConstraint testsimplefilesystem \
  [string equal testsimplefilesystem [info commands testsimplefilesystem]]

test filesystem-1.0 {link normalisation} {hasLinks} {
   string equal [file normalize gorp.file] [file normalize link.file]
} {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 macOrUnix} {
    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 macOrUnix} {
    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} {macOrUnix 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} {macOrUnix 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} {macOrUnix 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}
125
126
127
128
129
130
131
132


















































































































133
134
135


136

137






































































138
139
140
141
142
143
144
    file normalize C:/thislongnamedoesntexist
} {C:/thislongnamedoesntexist}

test filesystem-1.14 {file normalisation} {winOnly} {
    # This used to be broken
    file normalize c:/
} {C:/}



















































































































file delete -force dir2.file
file delete -force dir2.link
file delete -force link.file dir.link


removeFile [file join dir.file inside.file]

removeDirectory dir.file







































































test filesystem-2.0 {new native path} {unixOnly} {
   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








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



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







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
    file normalize C:/thislongnamedoesntexist
} {C:/thislongnamedoesntexist}

test filesystem-1.14 {file normalisation} {winOnly} {
    # This used to be broken
    file normalize c:/
} {C:/}

test filesystem-1.15 {file normalisation} {winOnly} {
    file normalize c:/../
} {C:/}

test filesystem-1.16 {file normalisation} {winOnly} {
    file normalize c:/.
} {C:/}

test filesystem-1.17 {file normalisation} {winOnly} {
    file normalize c:/..
} {C:/}

test filesystem-1.17.1 {file normalisation} {winOnly} {
    file normalize c:\\..
} {C:/}

test filesystem-1.18 {file normalisation} {winOnly} {
    file normalize c:/./
} {C:/}

test filesystem-1.19 {file normalisation} {winOnly} {
    file normalize w:/./../../..
} {w:/}

test filesystem-1.20 {file normalisation} {winOnly} {
    file normalize //name/foo/../
} {//name/foo}

test filesystem-1.21 {file normalisation} {winOnly} {
    file normalize C:///foo/./
} {C:/foo}

test filesystem-1.22 {file normalisation} {winOnly} {
    file normalize //name/foo/.
} {//name/foo}

test filesystem-1.23 {file normalisation} {winOnly} {
    file normalize c:/./foo
} {C:/foo}

test filesystem-1.24 {file normalisation} {winOnly} {
    file normalize w:/./../../../a
} {w:/a}

test filesystem-1.25 {file normalisation} {winOnly} {
    file normalize w:/./.././../../a
} {w:/a}

test filesystem-1.25.1 {file normalisation} {winOnly} {
    file normalize w:/./.././..\\..\\a\\bb
} {w:/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]]]
    if {![string equal [lindex $res 0] [lindex $res 1]]} {
	set res "$res not equal"
    } else {
	set res "ok"
    }
} {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]
    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]]]
    if {![string equal [lindex $res 0] [lindex $res 1]]} {
	set res "$res not equal"
    } else {
	set res "ok"
    }
} {ok}

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 first ".." $res] != -1} {
	set res "$res must not contain '..'"
    } else {
	set res "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]
removeDirectory dir.dir

test filesystem-1.30 {normalisation of nonexistent user} {
    list [catch {file normalize ~noonewiththisname} err] $err
} {1 {user "noonewiththisname" doesn't exist}}

test filesystem-1.31 {link normalisation: link near filesystem root} {testsetplatform} {
    testsetplatform unix
    file normalize /foo/../bar
} {/bar}

test filesystem-1.32 {link normalisation: link near filesystem root} {testsetplatform} {
    testsetplatform unix
    file normalize /../bar
} {/bar}

test filesystem-1.33 {link normalisation: link near filesystem root} {testsetplatform} {
    testsetplatform windows
    set res [file normalize C:/../bar]
    if {$::tcl_platform(platform) == "unix"} {
	# Some unices go further in normalizing this -- not really
	# a problem since this is a Windows test
	regexp {C:/bar$} $res res
    }
    set res
} {C:/bar}

if {[tcltest::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-2.0 {new native path} {unixOnly} {
   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
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
    -body {
	testfilesystem 1
	set filesystemReport {}
	file exists foo
	testfilesystem 0
	set filesystemReport
    }
    -result {* {access foo}}
}

test filesystem-4.1 {testfilesystem} {
    -constraints Tcltest
    -match glob
    -body {
	testfilesystem 1
	set filesystemReport {}
	catch {file stat foo bar}
	testfilesystem 0
	set filesystemReport
    }
    -result {* {stat foo}}
}

test filesystem-4.2 {testfilesystem} {
    -constraints Tcltest
    -match glob
    -body {
	testfilesystem 1
	set filesystemReport {}
	catch {file lstat foo bar}
	testfilesystem 0
	set filesystemReport
    }
    -result {* {lstat foo}}
}

test filesystem-4.3 {testfilesystem} {
    -constraints Tcltest
    -match glob
    -body {
	testfilesystem 1
	set filesystemReport {}
	catch {glob *}
	testfilesystem 0
	set filesystemReport
    }
    -result {* {matchindirectory *}*}
}

test filesystem-5.1 {cache and ~} {
    -constraints Tcltest
    -match regexp
    -body {
	set orig $env(HOME)







|












|












|












|







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
    -body {
	testfilesystem 1
	set filesystemReport {}
	file exists foo
	testfilesystem 0
	set filesystemReport
    }
    -result {*{access foo}}
}

test filesystem-4.1 {testfilesystem} {
    -constraints Tcltest
    -match glob
    -body {
	testfilesystem 1
	set filesystemReport {}
	catch {file stat foo bar}
	testfilesystem 0
	set filesystemReport
    }
    -result {*{stat foo}}
}

test filesystem-4.2 {testfilesystem} {
    -constraints Tcltest
    -match glob
    -body {
	testfilesystem 1
	set filesystemReport {}
	catch {file lstat foo bar}
	testfilesystem 0
	set filesystemReport
    }
    -result {*{lstat foo}}
}

test filesystem-4.3 {testfilesystem} {
    -constraints Tcltest
    -match glob
    -body {
	testfilesystem 1
	set filesystemReport {}
	catch {glob *}
	testfilesystem 0
	set filesystemReport
    }
    -result {*{matchindirectory *}*}
}

test filesystem-5.1 {cache and ~} {
    -constraints Tcltest
    -match regexp
    -body {
	set orig $env(HOME)
408
409
410
411
412
413
414


415
416
417
418
419
420


































































































































421
422
423

424
425
426
427
428
429
430

test filesystem-7.2 {cross-filesystem copy from vfs maintains mtime} \
  {testsimplefilesystem} {
    set dir [pwd]
    cd [tcltest::temporaryDirectory]
    # We created this file several tests ago.
    set origtime [file mtime gorp.file]


    testsimplefilesystem 1
    file delete -force theCopy
    file copy simplefs:/gorp.file theCopy
    testsimplefilesystem 0
    set newtime [file mtime theCopy]
    file delete theCopy


































































































































    cd $dir
    expr {$origtime == $newtime}
} {1}


removeFile gorp.file

test filesystem-8.1 {relative path objects and caching of pwd} {
    set dir [pwd]
    cd [tcltest::temporaryDirectory]
    makeDirectory abc







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

<
|
>







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

test filesystem-7.2 {cross-filesystem copy from vfs maintains mtime} \
  {testsimplefilesystem} {
    set dir [pwd]
    cd [tcltest::temporaryDirectory]
    # We created this file several tests ago.
    set origtime [file mtime gorp.file]
    set res [file exists gorp.file]
    if {[catch {
	testsimplefilesystem 1
	file delete -force theCopy
	file copy simplefs:/gorp.file theCopy
	testsimplefilesystem 0
	set newtime [file mtime theCopy]
	file delete theCopy
    } err]} {
	lappend res $err
	set newtime ""
    }
    cd $dir
    lappend res [expr {$origtime == $newtime}]
} {1 1}

test filesystem-7.3 {glob in simplefs} \
  {testsimplefilesystem} {
    set dir [pwd]
    cd [tcltest::temporaryDirectory]
    file mkdir simpledir
    close [open [file join simpledir simplefile] w]
    testsimplefilesystem 1
    set res [glob -nocomplain -dir simplefs:/simpledir *]
    testsimplefilesystem 0
    file delete -force simpledir
    cd $dir
    set res
} {simplefs:/simpledir/simplefile}

test filesystem-7.4 {cross-filesystem file copy with -force} \
  {testsimplefilesystem} {
    set dir [pwd]
    cd [tcltest::temporaryDirectory]
    set fout [open [file join simplefile] w]
    puts -nonewline $fout "1234567890"
    close $fout
    testsimplefilesystem 1
    # First copy should succeed
    set res [catch {file copy simplefs:/simplefile file2} err]
    lappend res $err
    # Second copy should fail (no -force)
    lappend res [catch {file copy simplefs:/simplefile file2} err]
    lappend res $err
    # Third copy should succeed (-force)
    lappend res [catch {file copy -force simplefs:/simplefile file2} err]
    lappend res $err
    lappend res [file exists file2]
    testsimplefilesystem 0
    file delete -force simplefile
    file delete -force file2
    cd $dir
    set res
} {0 10 1 {error copying "simplefs:/simplefile" to "file2": file already exists} 0 10 1}

test filesystem-7.5 {cross-filesystem file copy with -force} \
  {testsimplefilesystem unixOnly} {
    set dir [pwd]
    cd [tcltest::temporaryDirectory]
    set fout [open [file join simplefile] w]
    puts -nonewline $fout "1234567890"
    close $fout
    testsimplefilesystem 1
    # First copy should succeed
    set res [catch {file copy simplefs:/simplefile file2} err]
    lappend res $err
    file attributes file2 -permissions 0000
    # Second copy should fail (no -force)
    lappend res [catch {file copy simplefs:/simplefile file2} err]
    lappend res $err
    # Third copy should succeed (-force)
    lappend res [catch {file copy -force simplefs:/simplefile file2} err]
    lappend res $err
    lappend res [file exists file2]
    testsimplefilesystem 0
    file delete -force simplefile
    file delete -force file2
    cd $dir
    set res
} {0 10 1 {error copying "simplefs:/simplefile" to "file2": file already exists} 0 10 1}

test filesystem-7.6 {cross-filesystem dir copy with -force} \
  {testsimplefilesystem} {
    set dir [pwd]
    cd [tcltest::temporaryDirectory]
    file delete -force simpledir
    file mkdir simpledir
    file mkdir dir2
    set fout [open [file join simpledir simplefile] w]
    puts -nonewline $fout "1234567890"
    close $fout
    testsimplefilesystem 1
    # First copy should succeed
    set res [catch {file copy simplefs:/simpledir dir2} err]
    lappend res $err
    # Second copy should fail (no -force)
    lappend res [catch {file copy simplefs:/simpledir dir2} err]
    lappend res $err
    # Third copy should succeed (-force)
    lappend res [catch {file copy -force simplefs:/simpledir dir2} err]
    lappend res $err
    lappend res [file exists [file join dir2 simpledir]] \
      [file exists [file join dir2 simpledir simplefile]]
    testsimplefilesystem 0
    file delete -force simpledir
    file delete -force dir2
    cd $dir
    set res
} {0 {} 1 {error copying "simplefs:/simpledir" to "dir2/simpledir": file already exists} 0 {} 1 1}

test filesystem-7.7 {cross-filesystem dir copy with -force} \
  {testsimplefilesystem unixOnly} {
    set dir [pwd]
    cd [tcltest::temporaryDirectory]
    file delete -force simpledir
    file mkdir simpledir
    file mkdir dir2
    set fout [open [file join simpledir simplefile] w]
    puts -nonewline $fout "1234567890"
    close $fout
    testsimplefilesystem 1
    # First copy should succeed
    set res [catch {file copy simplefs:/simpledir dir2} err]
    lappend res $err
    # Second copy should fail (no -force)
    lappend res [catch {file copy simplefs:/simpledir dir2} err]
    lappend res $err
    # Third copy should succeed (-force)
    # I've noticed on some Unices that this only succeeds
    # intermittently (some runs work, some fail).  This needs
    # examining further.
    lappend res [catch {file copy -force simplefs:/simpledir dir2} err]
    lappend res $err
    lappend res [file exists [file join dir2 simpledir]] \
      [file exists [file join dir2 simpledir simplefile]]
    testsimplefilesystem 0
    file delete -force simpledir
    file delete -force dir2
    cd $dir

    set res
} {0 {} 1 {error copying "simplefs:/simpledir" to "dir2/simpledir": file already exists} 0 {} 1 1}

removeFile gorp.file

test filesystem-8.1 {relative path objects and caching of pwd} {
    set dir [pwd]
    cd [tcltest::temporaryDirectory]
    makeDirectory abc
Changes to tests/http.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Copyright (c) 1994-1996 Sun Microsystems, Inc.
# Copyright (c) 1998-2000 by Ajuba Solutions.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
#
# RCS: @(#) $Id: http.test,v 1.33.4.2 2003/08/07 21:36:04 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

if {[catch {package require http 2} version]} {







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Copyright (c) 1994-1996 Sun Microsystems, Inc.
# Copyright (c) 1998-2000 by Ajuba Solutions.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
#
# RCS: @(#) $Id: http.test,v 1.33.4.3 2004/02/07 05:48:02 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

if {[catch {package require http 2} version]} {
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
    catch {http::config -junk}
} 1

test http-1.4 {http::config} {
    set savedconf [http::config]
    http::config -proxyhost nowhere.come -proxyport 8080 -proxyfilter myFilter -useragent "Tcl Test Suite"
    set x [http::config]
    eval http::config $savedconf
    set x
} {-accept */* -proxyfilter myFilter -proxyhost nowhere.come -proxyport 8080 -useragent {Tcl Test Suite}}

test http-1.5 {http::config} {
    list [catch {http::config -proxyhost {} -junk 8080} msg] $msg
} {1 {Unknown option -junk, must be: -accept, -proxyfilter, -proxyhost, -proxyport, -useragent}}








|







96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
    catch {http::config -junk}
} 1

test http-1.4 {http::config} {
    set savedconf [http::config]
    http::config -proxyhost nowhere.come -proxyport 8080 -proxyfilter myFilter -useragent "Tcl Test Suite"
    set x [http::config]
    http::config {expand}$savedconf
    set x
} {-accept */* -proxyfilter myFilter -proxyhost nowhere.come -proxyport 8080 -useragent {Tcl Test Suite}}

test http-1.5 {http::config} {
    list [catch {http::config -proxyhost {} -junk 8080} msg] $msg
} {1 {Unknown option -junk, must be: -accept, -proxyfilter, -proxyhost, -proxyport, -useragent}}

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
22
23
24
25
26
27
28
# 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.
#
# RCS: @(#) $Id: init.test,v 1.9.4.2 2003/06/27 19:10:08 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

# Clear out any namespaces called test_ns_*
catch {eval namespace delete [namespace children :: test_ns_*]}

# Six cases - white box testing

test init-1.1 {auto_qualify - absolute cmd - namespace} {
    auto_qualify ::foo::bar ::blue
} ::foo::bar













|







|







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
# 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.
#
# RCS: @(#) $Id: init.test,v 1.9.4.3 2004/02/07 05:48:02 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

# Clear out any namespaces called test_ns_*
catch {namespace delete {expand}[namespace children :: test_ns_*]}

# Six cases - white box testing

test init-1.1 {auto_qualify - absolute cmd - namespace} {
    auto_qualify ::foo::bar ::blue
} ::foo::bar

Changes to tests/interp.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# This file tests the multiple interpreter facility of Tcl
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1995-1996 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.
#
# RCS: @(#) $Id: interp.test,v 1.22.2.2 2003/09/05 23:08:07 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2.1
    namespace import -force ::tcltest::*
}

# The set of hidden commands is platform dependent:












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# This file tests the multiple interpreter facility of Tcl
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1995-1996 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.
#
# RCS: @(#) $Id: interp.test,v 1.22.2.3 2004/02/07 05:48:02 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2.1
    namespace import -force ::tcltest::*
}

# The set of hidden commands is platform dependent:
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
	{knownBug} {
    # Test that all the possibles error codes from Tcl get passed
    # In both directions.  This doesn't work.
    set interp [interp create];
    proc MyTestAlias {interp args} {
	global aliasTrace;
	lappend aliasTrace $args;
	eval interp invokehidden [list $interp] $args
    }
    foreach c {return} {
	interp hide $interp  $c;
        interp alias $interp $c {} MyTestAlias $interp $c;
    }
    interp eval $interp {proc ret {code} {return -code $code ret$code}}
    set res {}







|







2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
	{knownBug} {
    # Test that all the possibles error codes from Tcl get passed
    # In both directions.  This doesn't work.
    set interp [interp create];
    proc MyTestAlias {interp args} {
	global aliasTrace;
	lappend aliasTrace $args;
	interp invokehidden $interp {expand}$args
    }
    foreach c {return} {
	interp hide $interp  $c;
        interp alias $interp $c {} MyTestAlias $interp $c;
    }
    interp eval $interp {proc ret {code} {return -code $code ret$code}}
    set res {}
Changes to tests/io.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Copyright (c) 1991-1994 The Regents of the University of California.
# Copyright (c) 1994-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.
#
# RCS: @(#) $Id: io.test,v 1.45.2.1 2003/10/16 02:28:03 dgp Exp $

if {[catch {package require tcltest 2}]} {
    puts stderr "Skipping tests in [info script].  tcltest 2 required."
    return
}
namespace eval ::tcl::test::io {








|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Copyright (c) 1991-1994 The Regents of the University of California.
# Copyright (c) 1994-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.
#
# RCS: @(#) $Id: io.test,v 1.45.2.2 2004/02/07 05:48:02 dgp Exp $

if {[catch {package require tcltest 2}]} {
    puts stderr "Skipping tests in [info script].  tcltest 2 required."
    return
}
namespace eval ::tcl::test::io {

2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
    set l ""
    lappend l [lsort [testchannel open]]
    set f [open $path(test1) w]
    lappend l [lsort [testchannel open]]
    close $f
    lappend l [lsort [testchannel open]]
    set x [list $consoleFileNames \
		[lsort [eval list $consoleFileNames $f]] \
		$consoleFileNames]
    string compare $l $x
} 0
test io-28.5 {Tcl_Close vs standard handles} {stdio unixOnly testchannel openpipe} {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f {







|







2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
    set l ""
    lappend l [lsort [testchannel open]]
    set f [open $path(test1) w]
    lappend l [lsort [testchannel open]]
    close $f
    lappend l [lsort [testchannel open]]
    set x [list $consoleFileNames \
		[lsort [list {expand}$consoleFileNames $f]] \
		$consoleFileNames]
    string compare $l $x
} 0
test io-28.5 {Tcl_Close vs standard handles} {stdio unixOnly testchannel openpipe} {
    file delete $path(script)
    set f [open $path(script) w]
    puts $f {
Changes to tests/ioUtil.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# This file (ioUtil.test) tests the hookable TclStat(), TclAccess(),
# and Tcl_OpenFileChannel, routines in the file generic/tclIOUtils.c.
# Sourcing this file into Tcl runs the tests and generates output for
# errors. No output means no errors were found. 
# 
# 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. 
# 
# RCS: @(#) $Id: ioUtil.test,v 1.14 2003/04/11 16:00:00 vincentdarley Exp $
 
if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

::tcltest::testConstraint testopenfilechannelproc \










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# This file (ioUtil.test) tests the hookable TclStat(), TclAccess(),
# and Tcl_OpenFileChannel, routines in the file generic/tclIOUtils.c.
# Sourcing this file into Tcl runs the tests and generates output for
# errors. No output means no errors were found. 
# 
# 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. 
# 
# RCS: @(#) $Id: ioUtil.test,v 1.14.2.1 2004/02/07 05:48:03 dgp Exp $
 
if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

::tcltest::testConstraint testopenfilechannelproc \
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
} {{"TestAccessProc1": could not be deleteed} {"TestAccessProc2": could not be deleteed} {"TestAccessProc3": could not be deleteed}}

# Some of the following tests require a writable current directory
set oldpwd [pwd]
cd [temporaryDirectory]

test ioUtil-3.1 {TclOpenFileChannel: Check that none of the test procs are there.} {testopenfilechannelproc} {
    catch {eval [list file delete -force] [glob *testOpenFileChannel*]}
    catch {file exists testOpenFileChannel1%.fil} err1
    catch {file exists testOpenFileChannel2%.fil} err2
    catch {file exists testOpenFileChannel3%.fil} err3
    catch {file exists __testOpenFileChannel1%__.fil} err4
    catch {file exists __testOpenFileChannel2%__.fil} err5
    catch {file exists __testOpenFileChannel3%__.fil} err6
    list $err1 $err2 $err3 $err4 $err5 $err6







|







187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
} {{"TestAccessProc1": could not be deleteed} {"TestAccessProc2": could not be deleteed} {"TestAccessProc3": could not be deleteed}}

# Some of the following tests require a writable current directory
set oldpwd [pwd]
cd [temporaryDirectory]

test ioUtil-3.1 {TclOpenFileChannel: Check that none of the test procs are there.} {testopenfilechannelproc} {
    catch {file delete -force {expand}[glob *testOpenFileChannel*]}
    catch {file exists testOpenFileChannel1%.fil} err1
    catch {file exists testOpenFileChannel2%.fil} err2
    catch {file exists testOpenFileChannel3%.fil} err3
    catch {file exists __testOpenFileChannel1%__.fil} err4
    catch {file exists __testOpenFileChannel2%__.fil} err5
    catch {file exists __testOpenFileChannel3%__.fil} err6
    list $err1 $err2 $err3 $err4 $err5 $err6
Changes to tests/iogt.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# -*- tcl -*-
# Commands covered:  transform, and stacking in general
#
# This file contains a collection of tests for Giot
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# Copyright (c) 2000 Ajuba Solutions.
# Copyright (c) 2000 Andreas Kupries.
# All rights reserved.
# 
# RCS: @(#) $Id: iogt.test,v 1.7 2002/07/04 15:46:55 andreas_kupries Exp $

if {[catch {package require tcltest 2.1}]} {
    puts stderr "Skipping tests in [info script].  tcltest 2.1 required."
    return
}
namespace eval ::tcl::test::iogt {













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# -*- tcl -*-
# Commands covered:  transform, and stacking in general
#
# This file contains a collection of tests for Giot
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# Copyright (c) 2000 Ajuba Solutions.
# Copyright (c) 2000 Andreas Kupries.
# All rights reserved.
# 
# RCS: @(#) $Id: iogt.test,v 1.7.4.1 2004/02/07 05:48:03 dgp Exp $

if {[catch {package require tcltest 2.1}]} {
    puts stderr "Skipping tests in [info script].  tcltest 2.1 required."
    return
}
namespace eval ::tcl::test::iogt {

143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
    # transmission, then hand over to the test script.
    # this has to start real transmission via 'flush'.
    # The server is stopped after completion of the test.

    # fixed port, not so good. lets hope for the best, for now.
    set port 4000

    eval exec tclsh __echo_srv__.tcl \
	    $port $fdelay $idelay $blocks >@stdout &

    after 500

    #puts stdout "> $port" ; flush stdout

    set         sk [socket localhost $port]
    fconfigure $sk           \







|
|







143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
    # transmission, then hand over to the test script.
    # this has to start real transmission via 'flush'.
    # The server is stopped after completion of the test.

    # fixed port, not so good. lets hope for the best, for now.
    set port 4000

    exec tclsh __echo_srv__.tcl \
	    $port $fdelay $idelay {expand}$blocks >@stdout &

    after 500

    #puts stdout "> $port" ; flush stdout

    set         sk [socket localhost $port]
    fconfigure $sk           \
Changes to tests/lindex.test.
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
# Copyright (c) 1994 Sun Microsystems, Inc.
# Copyright (c) 1998-1999 by Scriptics Corporation.
# Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: lindex.test,v 1.10 2002/04/19 13:08:56 dkf Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

set lindex lindex
set minus -


# Tests of Tcl_LindexObjCmd, NOT COMPILED

test lindex-1.1 {wrong # args} {
    list [catch {eval $lindex} result] $result
} "1 {wrong # args: should be \"lindex list ?index...?\"}"

# Indices that are lists or convertible to lists

test lindex-2.1 {empty index list} {
    set x {}
    list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]]
} {{a b c} {a b c}}

test lindex-2.2 {singleton index list} {
    set x { 1 }
    list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]]
} {b b}

test lindex-2.3 {multiple indices in list} {
    set x {1 2}
    list [eval [list $lindex {{a b c} {d e f}} $x]] \
	[eval [list $lindex {{a b c} {d e f}} $x]]
} {f f}

test lindex-2.4 {malformed index list} {
    set x \{
    list [catch { eval [list $lindex {a b c} $x] } result] $result
} {1 bad\ index\ \"\{\":\ must\ be\ integer\ or\ end?-integer?}

# Indices that are integers or convertible to integers

test lindex-3.1 {integer -1} {
    set x ${minus}1
    list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]]
} {{} {}}

test lindex-3.2 {integer 0} {
    set x [string range 00 0 0]
    list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]]
} {a a}

test lindex-3.3 {integer 2} {
    set x [string range 22 0 0]
    list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]]
} {c c}

test lindex-3.4 {integer 3} {
    set x [string range 33 0 0]
    list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]]
} {{} {}}

test lindex-3.5 {bad octal} {
    set x 08
    list [catch { eval [list $lindex {a b c} $x] } result] $result
} "1 {bad index \"08\": must be integer or end?-integer? (looks like invalid octal number)}"

test lindex-3.6 {bad octal} {
    set x -09
    list [catch { eval [list $lindex {a b c} $x] } result] $result
} "1 {bad index \"-09\": must be integer or end?-integer? (looks like invalid octal number)}"

test lindex-3.7 {indexes don't shimmer wide ints} {
    set x [expr {(wide(1)<<31) - 2}]
    list $x [lindex {1 2 3} $x] [incr x] [incr x]
} {2147483646 {} 2147483647 2147483648}

# Indices relative to end

test lindex-4.1 {index = end} {
    set x end
    list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]]
} {c c}

test lindex-4.2 {index = end--1} {
    set x end--1
    list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]]
} {{} {}}

test lindex-4.3 {index = end-0} {
    set x end-0
    list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]]
} {c c}

test lindex-4.4 {index = end-2} {
    set x end-2
    list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]]
} {a a}

test lindex-4.5 {index = end-3} {
    set x end-3
    list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]]
} {{} {}}

test lindex-4.6 {bad octal} {
    set x end-08
    list [catch { eval [list $lindex {a b c} $x] } result] $result
} "1 {bad index \"end-08\": must be integer or end?-integer? (looks like invalid octal number)}"

test lindex-4.7 {bad octal} {
    set x end--09
    list [catch { eval [list $lindex {a b c} $x] } result] $result
} "1 {bad index \"end--09\": must be integer or end?-integer?}"

test lindex-4.8 {bad integer, not octal} {
    set x end-0a2
    list [catch { eval [list $lindex {a b c} $x] } result] $result
} "1 {bad index \"end-0a2\": must be integer or end?-integer?}"

test lindex-4.9 {incomplete end} {
    set x en
    list [eval [list $lindex {a b c} $x]] [eval [list $lindex {a b c} $x]]
} {c c}

test lindex-4.10 {incomplete end-} {
    set x end-
    list [catch { eval [list $lindex {a b c} $x] } result] $result
} "1 {bad index \"end-\": must be integer or end?-integer?}"

test lindex-5.1 {bad second index} {
    list [catch { eval [list $lindex {a b c} 0 0a2] } result] $result
} "1 {bad index \"0a2\": must be integer or end?-integer?}"

test lindex-5.2 {good second index} {
    eval [list $lindex {{a b c} {d e f} {g h i}} 1 2]
} f

test lindex-5.3 {three indices} {
    eval [list $lindex {{{a b} {c d}} {{e f} {g h}}} 1 0 1]
} f
test lindex-6.1 {error conditions in parsing list} {
    list [catch {eval [list $lindex "a \{" 2]} msg] $msg
} {1 {unmatched open brace in list}}
test lindex-6.2 {error conditions in parsing list} {
    list [catch {eval [list $lindex {a {b c}d e} 2]} msg] $msg
} {1 {list element in braces followed by "d" instead of space}}
test lindex-6.3 {error conditions in parsing list} {
    list [catch {eval [list $lindex {a "b c"def ghi} 2]} msg] $msg
} {1 {list element in quotes followed by "def" instead of space}}

test lindex-7.1 {quoted elements} {
    eval [list $lindex {a "b c" d} 1]
} {b c}
test lindex-7.2 {quoted elements} {
    eval [list $lindex {"{}" b c} 0]
} {{}}
test lindex-7.3 {quoted elements} {
    eval [list $lindex {ab "c d \" x" y} 1]
} {c d " x}
test lindex-7.4 {quoted elements} {
    lindex {a b {c d "e} {f g"}} 2
} {c d "e}

test lindex-8.1 {data reuse} {
    set x 0
    eval [list $lindex $x $x]
} {0}

test lindex-8.2 {data reuse} {
    set a 0
    eval [list $lindex $a $a $a]
} 0
test lindex-8.3 {data reuse} {
    set a 1
    eval [list $lindex $a $a $a]
} {}

test lindex-8.4 {data reuse} {
    set x [list 0 0]
    eval [list $lindex $x $x]
} {0}

test lindex-8.5 {data reuse} {
    set x 0
    eval [list $lindex $x [list $x $x]]
} {0}

test lindex-8.6 {data reuse} {
    set x [list 1 1]
    eval [list $lindex $x $x]
} {}

test lindex-8.7 {data reuse} {
    set x 1
    eval [list lindex $x [list $x $x]]
} {}

#----------------------------------------------------------------------

# Compilation tests for lindex

test lindex-9.1 {wrong # args} {







|






<

>



|
|




|

|


|

|


|

|
|


|

|




|

|


|

|


|

|


|

|


|

|


|

|









|

|


|

|


|

|


|

|


|

|


|

|


|

|


|

|


|

|


|

|


|
|


|
|


|
|

|
|

|
|

|
|


|
|

|
|

|
|





|

|


|

|

|

|


|

|


|

|


|

|


|

|







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
# Copyright (c) 1994 Sun Microsystems, Inc.
# Copyright (c) 1998-1999 by Scriptics Corporation.
# Copyright (c) 2001 by Kevin B. Kenny.  All rights reserved.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: lindex.test,v 1.10.4.1 2004/02/07 05:48:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}


set minus -
testConstraint testevalex [llength [info commands testevalex]]

# Tests of Tcl_LindexObjCmd, NOT COMPILED

test lindex-1.1 {wrong # args} testevalex {
    list [catch {testevalex lindex} result] $result
} "1 {wrong # args: should be \"lindex list ?index...?\"}"

# Indices that are lists or convertible to lists

test lindex-2.1 {empty index list} testevalex {
    set x {}
    list [testevalex {lindex {a b c} $x}] [testevalex {lindex {a b c} $x}]
} {{a b c} {a b c}}

test lindex-2.2 {singleton index list} testevalex {
    set x { 1 }
    list [testevalex {lindex {a b c} $x}] [testevalex {lindex {a b c} $x}]
} {b b}

test lindex-2.3 {multiple indices in list} testevalex {
    set x {1 2}
    list [testevalex {lindex {{a b c} {d e f}} $x}] \
	[testevalex {lindex {{a b c} {d e f}} $x}]
} {f f}

test lindex-2.4 {malformed index list} testevalex {
    set x \{
    list [catch { testevalex {lindex {a b c} $x} } result] $result
} {1 bad\ index\ \"\{\":\ must\ be\ integer\ or\ end?-integer?}

# Indices that are integers or convertible to integers

test lindex-3.1 {integer -1} testevalex {
    set x ${minus}1
    list [testevalex {lindex {a b c} $x}] [testevalex {lindex {a b c} $x}]
} {{} {}}

test lindex-3.2 {integer 0} testevalex {
    set x [string range 00 0 0]
    list [testevalex {lindex {a b c} $x}] [testevalex {lindex {a b c} $x}]
} {a a}

test lindex-3.3 {integer 2} testevalex {
    set x [string range 22 0 0]
    list [testevalex {lindex {a b c} $x}] [testevalex {lindex {a b c} $x}]
} {c c}

test lindex-3.4 {integer 3} testevalex {
    set x [string range 33 0 0]
    list [testevalex {lindex {a b c} $x}] [testevalex {lindex {a b c} $x}]
} {{} {}}

test lindex-3.5 {bad octal} testevalex {
    set x 08
    list [catch { testevalex {lindex {a b c} $x} } result] $result
} "1 {bad index \"08\": must be integer or end?-integer? (looks like invalid octal number)}"

test lindex-3.6 {bad octal} testevalex {
    set x -09
    list [catch { testevalex {lindex {a b c} $x} } result] $result
} "1 {bad index \"-09\": must be integer or end?-integer? (looks like invalid octal number)}"

test lindex-3.7 {indexes don't shimmer wide ints} {
    set x [expr {(wide(1)<<31) - 2}]
    list $x [lindex {1 2 3} $x] [incr x] [incr x]
} {2147483646 {} 2147483647 2147483648}

# Indices relative to end

test lindex-4.1 {index = end} testevalex {
    set x end
    list [testevalex {lindex {a b c} $x}] [testevalex {lindex {a b c} $x}]
} {c c}

test lindex-4.2 {index = end--1} testevalex {
    set x end--1
    list [testevalex {lindex {a b c} $x}] [testevalex {lindex {a b c} $x}]
} {{} {}}

test lindex-4.3 {index = end-0} testevalex {
    set x end-0
    list [testevalex {lindex {a b c} $x}] [testevalex {lindex {a b c} $x}]
} {c c}

test lindex-4.4 {index = end-2} testevalex {
    set x end-2
    list [testevalex {lindex {a b c} $x}] [testevalex {lindex {a b c} $x}]
} {a a}

test lindex-4.5 {index = end-3} testevalex {
    set x end-3
    list [testevalex {lindex {a b c} $x}] [testevalex {lindex {a b c} $x}]
} {{} {}}

test lindex-4.6 {bad octal} testevalex {
    set x end-08
    list [catch { testevalex {lindex {a b c} $x} } result] $result
} "1 {bad index \"end-08\": must be integer or end?-integer? (looks like invalid octal number)}"

test lindex-4.7 {bad octal} testevalex {
    set x end--09
    list [catch { testevalex {lindex {a b c} $x} } result] $result
} "1 {bad index \"end--09\": must be integer or end?-integer?}"

test lindex-4.8 {bad integer, not octal} testevalex {
    set x end-0a2
    list [catch { testevalex {lindex {a b c} $x} } result] $result
} "1 {bad index \"end-0a2\": must be integer or end?-integer?}"

test lindex-4.9 {incomplete end} testevalex {
    set x en
    list [testevalex {lindex {a b c} $x}] [testevalex {lindex {a b c} $x}]
} {c c}

test lindex-4.10 {incomplete end-} testevalex {
    set x end-
    list [catch { testevalex {lindex {a b c} $x} } result] $result
} "1 {bad index \"end-\": must be integer or end?-integer?}"

test lindex-5.1 {bad second index} testevalex {
    list [catch { testevalex {lindex {a b c} 0 0a2} } result] $result
} "1 {bad index \"0a2\": must be integer or end?-integer?}"

test lindex-5.2 {good second index} testevalex {
    testevalex {lindex {{a b c} {d e f} {g h i}} 1 2}
} f

test lindex-5.3 {three indices} testevalex {
    testevalex {lindex {{{a b} {c d}} {{e f} {g h}}} 1 0 1}
} f
test lindex-6.1 {error conditions in parsing list} testevalex {
    list [catch {testevalex {lindex "a \{" 2}} msg] $msg
} {1 {unmatched open brace in list}}
test lindex-6.2 {error conditions in parsing list} testevalex {
    list [catch {testevalex {lindex {a {b c}d e} 2}} msg] $msg
} {1 {list element in braces followed by "d" instead of space}}
test lindex-6.3 {error conditions in parsing list} testevalex {
    list [catch {testevalex {lindex {a "b c"def ghi} 2}} msg] $msg
} {1 {list element in quotes followed by "def" instead of space}}

test lindex-7.1 {quoted elements} testevalex {
    testevalex {lindex {a "b c" d} 1}
} {b c}
test lindex-7.2 {quoted elements} testevalex {
    testevalex {lindex {"{}" b c} 0}
} {{}}
test lindex-7.3 {quoted elements} testevalex {
    testevalex {lindex {ab "c d \" x" y} 1}
} {c d " x}
test lindex-7.4 {quoted elements} {
    lindex {a b {c d "e} {f g"}} 2
} {c d "e}

test lindex-8.1 {data reuse} testevalex {
    set x 0
    testevalex {lindex $x $x}
} {0}

test lindex-8.2 {data reuse} testevalex {
    set a 0
    testevalex {lindex $a $a $a}
} 0
test lindex-8.3 {data reuse} testevalex {
    set a 1
    testevalex {lindex $a $a $a}
} {}

test lindex-8.4 {data reuse} testevalex {
    set x [list 0 0]
    testevalex {lindex $x $x}
} {0}

test lindex-8.5 {data reuse} testevalex {
    set x 0
    testevalex {lindex $x [list $x $x]}
} {0}

test lindex-8.6 {data reuse} testevalex {
    set x [list 1 1]
    testevalex {lindex $x $x}
} {}

test lindex-8.7 {data reuse} testevalex {
    set x 1
    testevalex {lindex $x [list $x $x]}
} {}

#----------------------------------------------------------------------

# Compilation tests for lindex

test lindex-9.1 {wrong # args} {
465
466
467
468
469
470
471
472
473
474
475
476
477
    set x 1
    catch {
	lindex $x [list $x $x]
    } result
    set result
} {}

catch { unset lindex}
catch { unset minus }

# cleanup
::tcltest::cleanupTests
return







<





465
466
467
468
469
470
471

472
473
474
475
476
    set x 1
    catch {
	lindex $x [list $x $x]
    } result
    set result
} {}


catch { unset minus }

# cleanup
::tcltest::cleanupTests
return
Changes to tests/lset.test.
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
    namespace import -force ::tcltest::*
}

proc failTrace {name1 name2 op} {
    error "trace failed"
}

set lset lset

set noRead {}
trace add variable noRead read failTrace
set noWrite {a b c}
trace add variable noWrite write failTrace

test lset-1.1 {lset, not compiled, arg count} {
    list [catch {eval $lset} msg] $msg
} "1 {wrong \# args: should be \"lset listVar index ?index...? value\"}"

test lset-1.2 {lset, not compiled, no such var} {
    list [catch {eval [list $lset noSuchVar 0 {}]} msg] $msg
} "1 {can't read \"noSuchVar\": no such variable}"

test lset-1.3 {lset, not compiled, var not readable} {
    list [catch {eval [list $lset noRead 0 {}]} msg] $msg
} "1 {can't read \"noRead\": trace failed}"

test lset-2.1 {lset, not compiled, 3 args, second arg a plain index} {
    set x {0 1 2}
    list [eval [list $lset x 0 3]] $x
} {{3 1 2} {3 1 2}}

test lset-2.2 {lset, not compiled, 3 args, second arg neither index nor list} {
    set x {0 1 2}
    list [catch {
	eval [list $lset x {{bad}1} 3]
    } msg] $msg
} "1 {bad index \"{bad}1\": must be integer or end?-integer?}"

test lset-3.1 {lset, not compiled, 3 args, data duplicated} {
    set x {0 1 2}
    list [eval [list $lset x 0 $x]] $x
} {{{0 1 2} 1 2} {{0 1 2} 1 2}}

test lset-3.2 {lset, not compiled, 3 args, data duplicated} {
    set x {0 1}
    set y $x
    list [eval [list $lset x 0 2]] $x $y
} {{2 1} {2 1} {0 1}}

test lset-3.3 {lset, not compiled, 3 args, data duplicated} {
    set x {0 1}
    set y $x
    list [eval [list $lset x 0 $x]] $x $y
} {{{0 1} 1} {{0 1} 1} {0 1}}

test lset-3.4 {lset, not compiled, 3 args, data duplicated} {
    set x {0 1 2}
    list [eval [list $lset x [list 0] $x]] $x
} {{{0 1 2} 1 2} {{0 1 2} 1 2}}

test lset-3.5 {lset, not compiled, 3 args, data duplicated} {
    set x {0 1}
    set y $x
    list [eval [list $lset x [list 0] 2]] $x $y
} {{2 1} {2 1} {0 1}}

test lset-3.6 {lset, not compiled, 3 args, data duplicated} {
    set x {0 1}
    set y $x
    list [eval [list $lset x [list 0] $x]] $x $y
} {{{0 1} 1} {{0 1} 1} {0 1}}

test lset-4.1 {lset, not compiled, 3 args, not a list} {
    set a "x \{"
    list [catch {
	eval [list $lset a [list 0] y]
    } msg] $msg
} {1 {unmatched open brace in list}}

test lset-4.2 {lset, not compiled, 3 args, bad index} {
    set a {x y z}
    list [catch {
	eval [list $lset a [list 2a2] w]
    } msg] $msg
} {1 {bad index "2a2": must be integer or end?-integer?}}

test lset-4.3 {lset, not compiled, 3 args, index out of range} {
    set a {x y z}
    list [catch {
	eval [list $lset a [list -1] w]
    } msg] $msg
} {1 {list index out of range}}

test lset-4.4 {lset, not compiled, 3 args, index out of range} {
    set a {x y z}
    list [catch {
	eval [list $lset a [list 3] w]
    } msg] $msg
} {1 {list index out of range}}

test lset-4.5 {lset, not compiled, 3 args, index out of range} {
    set a {x y z}
    list [catch {
	eval [list $lset a [list end--1] w]
    } msg] $msg
} {1 {list index out of range}}

test lset-4.6 {lset, not compiled, 3 args, index out of range} {
    set a {x y z}
    list [catch {
	eval [list $lset a [list end-3] w]
    } msg] $msg
} {1 {list index out of range}}

test lset-4.7 {lset, not compiled, 3 args, not a list} {
    set a "x \{"
    list [catch {
	eval [list $lset a 0 y]
    } msg] $msg
} {1 {unmatched open brace in list}}

test lset-4.8 {lset, not compiled, 3 args, bad index} {
    set a {x y z}
    list [catch {
	eval [list $lset a 2a2 w]
    } msg] $msg
} {1 {bad index "2a2": must be integer or end?-integer?}}

test lset-4.9 {lset, not compiled, 3 args, index out of range} {
    set a {x y z}
    list [catch {
	eval [list $lset a -1 w]
    } msg] $msg
} {1 {list index out of range}}

test lset-4.10 {lset, not compiled, 3 args, index out of range} {
    set a {x y z}
    list [catch {
	eval [list $lset a 3 w]
    } msg] $msg
} {1 {list index out of range}}

test lset-4.11 {lset, not compiled, 3 args, index out of range} {
    set a {x y z}
    list [catch {
	eval [list $lset a end--1 w]
    } msg] $msg
} {1 {list index out of range}}

test lset-4.12 {lset, not compiled, 3 args, index out of range} {
    set a {x y z}
    list [catch {
	eval [list $lset a end-3 w]
    } msg] $msg
} {1 {list index out of range}}

test lset-5.1 {lset, not compiled, 3 args, can't set variable} {
    list [catch {
	eval [list $lset noWrite 0 d]
    } msg] $msg $noWrite
} {1 {can't set "noWrite": trace failed} {d b c}}

test lset-5.2 {lset, not compiled, 3 args, can't set variable} {
    list [catch {
	eval [list $lset noWrite [list 0] d]
    } msg] $msg $noWrite
} {1 {can't set "noWrite": trace failed} {d b c}}

test lset-6.1 {lset, not compiled, 3 args, 1-d list basics} {
    set a {x y z}
    list [eval [list $lset a 0 a]] $a
} {{a y z} {a y z}}

test lset-6.2 {lset, not compiled, 3 args, 1-d list basics} {
    set a {x y z}
    list [eval [list $lset a [list 0] a]] $a
} {{a y z} {a y z}}

test lset-6.3 {lset, not compiled, 1-d list basics} {
    set a {x y z}
    list [eval [list $lset a 2 a]] $a
} {{x y a} {x y a}}



test lset-6.4 {lset, not compiled, 1-d list basics} {
    set a {x y z}
    list [eval [list $lset a [list 2] a]] $a
} {{x y a} {x y a}}

test lset-6.5 {lset, not compiled, 1-d list basics} {
    set a {x y z}
    list [eval [list $lset a end a]] $a
} {{x y a} {x y a}}

test lset-6.6 {lset, not compiled, 1-d list basics} {
    set a {x y z}
    list [eval [list $lset a [list end] a]] $a
} {{x y a} {x y a}}

test lset-6.7 {lset, not compiled, 1-d list basics} {
    set a {x y z}
    list [eval [list $lset a end-0 a]] $a
} {{x y a} {x y a}}

test lset-6.8 {lset, not compiled, 1-d list basics} {
    set a {x y z}
    list [eval [list $lset a [list end-0] a]] $a
} {{x y a} {x y a}}

test lset-6.9 {lset, not compiled, 1-d list basics} {
    set a {x y z}
    list [eval [list $lset a end-2 a]] $a
} {{a y z} {a y z}}

test lset-6.10 {lset, not compiled, 1-d list basics} {
    set a {x y z}
    list [eval [list $lset a [list end-2] a]] $a
} {{a y z} {a y z}}

test lset-7.1 {lset, not compiled, data sharing} {
    set a 0
    list [eval [list $lset a $a {gag me}]] $a
} {{{gag me}} {{gag me}}}

test lset-7.2 {lset, not compiled, data sharing} {
    set a [list 0]
    list [eval [list $lset a $a {gag me}]] $a
} {{{gag me}} {{gag me}}}

test lset-7.3 {lset, not compiled, data sharing} {
    set a {x y}
    list [eval [list $lset a 0 $a]] $a
} {{{x y} y} {{x y} y}}

test lset-7.4 {lset, not compiled, data sharing} {
    set a {x y}
    list [eval [list $lset a [list 0] $a]] $a
} {{{x y} y} {{x y} y}}

test lset-7.5 {lset, not compiled, data sharing} {
    set n 0
    set a {x y}
    list [eval [list $lset a $n $n]] $a $n
} {{0 y} {0 y} 0}

test lset-7.6 {lset, not compiled, data sharing} {
    set n [list 0]
    set a {x y}
    list [eval [list $lset a $n $n]] $a $n
} {{0 y} {0 y} 0}

test lset-7.7 {lset, not compiled, data sharing} {
    set n 0
    set a [list $n $n]
    list [eval [list $lset a $n 1]] $a $n
} {{1 0} {1 0} 0}

test lset-7.8 {lset, not compiled, data sharing} {
    set n [list 0]
    set a [list $n $n]
    list [eval [list $lset a $n 1]] $a $n
} {{1 0} {1 0} 0}

test lset-7.9 {lset, not compiled, data sharing} {
    set a 0
    list [eval [list $lset a $a $a]] $a
} {0 0}

test lset-7.10 {lset, not compiled, data sharing} {
    set a [list 0]
    list [eval [list $lset a $a $a]] $a
} {0 0}

test lset-8.1 {lset, not compiled, malformed sublist} {
    set a [list "a \{" b]
    list [catch {eval [list $lset a 0 1 c]} msg] $msg
} {1 {unmatched open brace in list}}

test lset-8.2 {lset, not compiled, malformed sublist} {
    set a [list "a \{" b]
    list [catch {eval [list $lset a {0 1} c]} msg] $msg
} {1 {unmatched open brace in list}}

test lset-8.3 {lset, not compiled, bad second index} {
    set a {{b c} {d e}}
    list [catch {eval [list $lset a 0 2a2 f]} msg] $msg
} {1 {bad index "2a2": must be integer or end?-integer?}}

test lset-8.4 {lset, not compiled, bad second index} {
    set a {{b c} {d e}}
    list [catch {eval [list $lset a {0 2a2} f]} msg] $msg
} {1 {bad index "2a2": must be integer or end?-integer?}}

test lset-8.5 {lset, not compiled, second index out of range} {
    set a {{b c} {d e} {f g}}
    list [catch {eval [list $lset a 2 -1 h]} msg] $msg
} {1 {list index out of range}}

test lset-8.6 {lset, not compiled, second index out of range} {
    set a {{b c} {d e} {f g}}
    list [catch {eval [list $lset a {2 -1} h]} msg] $msg
} {1 {list index out of range}}



test lset-8.7 {lset, not compiled, second index out of range} {
    set a {{b c} {d e} {f g}}
    list [catch {eval [list $lset a 2 2 h]} msg] $msg
} {1 {list index out of range}}

test lset-8.8 {lset, not compiled, second index out of range} {
    set a {{b c} {d e} {f g}}
    list [catch {eval [list $lset a {2 2} h]} msg] $msg
} {1 {list index out of range}}

test lset-8.9 {lset, not compiled, second index out of range} {
    set a {{b c} {d e} {f g}}
    list [catch {eval [list $lset a 2 end--1 h]} msg] $msg
} {1 {list index out of range}}

test lset-8.10 {lset, not compiled, second index out of range} {
    set a {{b c} {d e} {f g}}
    list [catch {eval [list $lset a {2 end--1} h]} msg] $msg
} {1 {list index out of range}}

test lset-8.11 {lset, not compiled, second index out of range} {
    set a {{b c} {d e} {f g}}
    list [catch {eval [list $lset a 2 end-2 h]} msg] $msg
} {1 {list index out of range}}

test lset-8.12 {lset, not compiled, second index out of range} {
    set a {{b c} {d e} {f g}}
    list [catch {eval [list $lset a {2 end-2} h]} msg] $msg
} {1 {list index out of range}}

test lset-9.1 {lset, not compiled, entire variable} {
    set a x
    list [eval [list $lset a y]] $a
} {y y}

test lset-9.2 {lset, not compiled, entire variable} {
    set a x
    list [eval [list $lset a {} y]] $a
} {y y}

test lset-10.1 {lset, not compiled, shared data} {
    set row {p q}
    set a [list $row $row]
    list [eval [list $lset a 0 0 x]] $a
} {{{x q} {p q}} {{x q} {p q}}}

test lset-10.2 {lset, not compiled, shared data} {
    set row {p q}
    set a [list $row $row]
    list [eval [list $lset a {0 0} x]] $a
} {{{x q} {p q}} {{x q} {p q}}}

test lset-11.1 {lset, not compiled, 2-d basics} {
    set a {{b c} {d e}}
    list [eval [list $lset a 0 0 f]] $a
} {{{f c} {d e}} {{f c} {d e}}}

test lset-11.2 {lset, not compiled, 2-d basics} {
    set a {{b c} {d e}}
    list [eval [list $lset a {0 0} f]] $a
} {{{f c} {d e}} {{f c} {d e}}}

test lset-11.3 {lset, not compiled, 2-d basics} {
    set a {{b c} {d e}}
    list [eval [list $lset a 0 1 f]] $a
} {{{b f} {d e}} {{b f} {d e}}}

test lset-11.4 {lset, not compiled, 2-d basics} {
    set a {{b c} {d e}}
    list [eval [list $lset a {0 1} f]] $a
} {{{b f} {d e}} {{b f} {d e}}}



test lset-11.5 {lset, not compiled, 2-d basics} {
    set a {{b c} {d e}}
    list [eval [list $lset a 1 0 f]] $a
} {{{b c} {f e}} {{b c} {f e}}}

test lset-11.6 {lset, not compiled, 2-d basics} {
    set a {{b c} {d e}}
    list [eval [list $lset a {1 0} f]] $a
} {{{b c} {f e}} {{b c} {f e}}}

test lset-11.7 {lset, not compiled, 2-d basics} {
    set a {{b c} {d e}}
    list [eval [list $lset a 1 1 f]] $a
} {{{b c} {d f}} {{b c} {d f}}}

test lset-11.8 {lset, not compiled, 2-d basics} {
    set a {{b c} {d e}}
    list [eval [list $lset a {1 1} f]] $a
} {{{b c} {d f}} {{b c} {d f}}}

test lset-12.0 {lset, not compiled, typical sharing pattern} {
    set zero 0
    set row [list $zero $zero $zero $zero]
    set ident [list $row $row $row $row]
    for { set i 0 } { $i < 4 } { incr i } {
	eval [list $lset ident $i $i 1]
    }
    set ident
} {{1 0 0 0} {0 1 0 0} {0 0 1 0} {0 0 0 1}}

test lset-13.0 {lset, not compiled, shimmering hell} {
    set a 0
    list [eval [list $lset a $a $a $a $a {gag me}]] $a
} {{{{{{gag me}}}}} {{{{{gag me}}}}}}

test lset-13.1 {lset, not compiled, shimmering hell} {
    set a [list 0]
    list [eval [list $lset a $a $a $a $a {gag me}]] $a
} {{{{{{gag me}}}}} {{{{{gag me}}}}}}

test lset-13.2 {lset, not compiled, shimmering hell} {
    set a [list 0 0 0 0]
    list [eval [list $lset a $a {gag me}]] $a
} {{{{{{gag me}}}} 0 0 0} {{{{{gag me}}}} 0 0 0}}

test lset-14.1 {lset, not compiled, list args, is string rep preserved?} {
    set a { { 1 2 } { 3 4 } }
    catch { eval [list $lset a {1 5} 5] }
    list $a [lindex $a 1]
} "{ { 1 2 } { 3 4 } } { 3 4 }"

test lset-14.2 {lset, not compiled, flat args, is string rep preserved?} {
    set a { { 1 2 } { 3 4 } }
    catch { eval [list $lset a 1 5 5] }
    list $a [lindex $a 1]
} "{ { 1 2 } { 3 4 } } { 3 4 }"

catch {unset noRead}
catch {unset noWrite}
catch {rename failTrace {}}
catch {unset ::x}







|






|
|


|
|


|
|


|

|


|


|



|

|


|


|


|


|


|

|


|


|


|


|


|


|



|


|



|


|



|


|



|


|



|


|



|


|



|


|



|


|



|


|



|


|



|


|



|

|



|

|



|

|


|

|


|

<
<
>
>

|

|


|

|


|

|


|

|


|

|


|

|


|

|


|

|


|

|


|

|


|

|


|


|


|


|


|


|


|


|


|

|


|

|


|

|


|

|


|

|


|

|


|

|


|

<
<
>
>

|

|


|

|


|

|


|

|


|

|


|

|


|

|


|

|


|


|


|


|


|

|


|

|


|

|


|

<
<
>
>

|

|


|

|


|

|


|

|


|




|




|

|


|

|


|

|


|

|



|

|







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
    namespace import -force ::tcltest::*
}

proc failTrace {name1 name2 op} {
    error "trace failed"
}

testConstraint testevalex [llength [info commands testevalex]]

set noRead {}
trace add variable noRead read failTrace
set noWrite {a b c}
trace add variable noWrite write failTrace

test lset-1.1 {lset, not compiled, arg count} testevalex {
    list [catch {testevalex lset} msg] $msg
} "1 {wrong \# args: should be \"lset listVar index ?index...? value\"}"

test lset-1.2 {lset, not compiled, no such var} testevalex {
    list [catch {testevalex {lset noSuchVar 0 {}}} msg] $msg
} "1 {can't read \"noSuchVar\": no such variable}"

test lset-1.3 {lset, not compiled, var not readable} testevalex {
    list [catch {testevalex {lset noRead 0 {}}} msg] $msg
} "1 {can't read \"noRead\": trace failed}"

test lset-2.1 {lset, not compiled, 3 args, second arg a plain index} testevalex {
    set x {0 1 2}
    list [testevalex {lset x 0 3}] $x
} {{3 1 2} {3 1 2}}

test lset-2.2 {lset, not compiled, 3 args, second arg neither index nor list} testevalex {
    set x {0 1 2}
    list [catch {
	testevalex {lset x {{bad}1} 3}
    } msg] $msg
} "1 {bad index \"{bad}1\": must be integer or end?-integer?}"

test lset-3.1 {lset, not compiled, 3 args, data duplicated} testevalex {
    set x {0 1 2}
    list [testevalex {lset x 0 $x}] $x
} {{{0 1 2} 1 2} {{0 1 2} 1 2}}

test lset-3.2 {lset, not compiled, 3 args, data duplicated} testevalex {
    set x {0 1}
    set y $x
    list [testevalex {lset x 0 2}] $x $y
} {{2 1} {2 1} {0 1}}

test lset-3.3 {lset, not compiled, 3 args, data duplicated} testevalex {
    set x {0 1}
    set y $x
    list [testevalex {lset x 0 $x}] $x $y
} {{{0 1} 1} {{0 1} 1} {0 1}}

test lset-3.4 {lset, not compiled, 3 args, data duplicated} testevalex {
    set x {0 1 2}
    list [testevalex {lset x [list 0] $x}] $x
} {{{0 1 2} 1 2} {{0 1 2} 1 2}}

test lset-3.5 {lset, not compiled, 3 args, data duplicated} testevalex {
    set x {0 1}
    set y $x
    list [testevalex {lset x [list 0] 2}] $x $y
} {{2 1} {2 1} {0 1}}

test lset-3.6 {lset, not compiled, 3 args, data duplicated} testevalex {
    set x {0 1}
    set y $x
    list [testevalex {lset x [list 0] $x}] $x $y
} {{{0 1} 1} {{0 1} 1} {0 1}}

test lset-4.1 {lset, not compiled, 3 args, not a list} testevalex {
    set a "x \{"
    list [catch {
	testevalex {lset a [list 0] y}
    } msg] $msg
} {1 {unmatched open brace in list}}

test lset-4.2 {lset, not compiled, 3 args, bad index} testevalex {
    set a {x y z}
    list [catch {
	testevalex {lset a [list 2a2] w}
    } msg] $msg
} {1 {bad index "2a2": must be integer or end?-integer?}}

test lset-4.3 {lset, not compiled, 3 args, index out of range} testevalex {
    set a {x y z}
    list [catch {
	testevalex {lset a [list -1] w}
    } msg] $msg
} {1 {list index out of range}}

test lset-4.4 {lset, not compiled, 3 args, index out of range} testevalex {
    set a {x y z}
    list [catch {
	testevalex {lset a [list 3] w}
    } msg] $msg
} {1 {list index out of range}}

test lset-4.5 {lset, not compiled, 3 args, index out of range} testevalex {
    set a {x y z}
    list [catch {
	testevalex {lset a [list end--1] w}
    } msg] $msg
} {1 {list index out of range}}

test lset-4.6 {lset, not compiled, 3 args, index out of range} testevalex {
    set a {x y z}
    list [catch {
	testevalex {lset a [list end-3] w}
    } msg] $msg
} {1 {list index out of range}}

test lset-4.7 {lset, not compiled, 3 args, not a list} testevalex {
    set a "x \{"
    list [catch {
	testevalex {lset a 0 y}
    } msg] $msg
} {1 {unmatched open brace in list}}

test lset-4.8 {lset, not compiled, 3 args, bad index} testevalex {
    set a {x y z}
    list [catch {
	testevalex {lset a 2a2 w}
    } msg] $msg
} {1 {bad index "2a2": must be integer or end?-integer?}}

test lset-4.9 {lset, not compiled, 3 args, index out of range} testevalex {
    set a {x y z}
    list [catch {
	testevalex {lset a -1 w}
    } msg] $msg
} {1 {list index out of range}}

test lset-4.10 {lset, not compiled, 3 args, index out of range} testevalex {
    set a {x y z}
    list [catch {
	testevalex {lset a 3 w}
    } msg] $msg
} {1 {list index out of range}}

test lset-4.11 {lset, not compiled, 3 args, index out of range} testevalex {
    set a {x y z}
    list [catch {
	testevalex {lset a end--1 w}
    } msg] $msg
} {1 {list index out of range}}

test lset-4.12 {lset, not compiled, 3 args, index out of range} testevalex {
    set a {x y z}
    list [catch {
	testevalex {lset a end-3 w}
    } msg] $msg
} {1 {list index out of range}}

test lset-5.1 {lset, not compiled, 3 args, can't set variable} testevalex {
    list [catch {
	testevalex {lset noWrite 0 d}
    } msg] $msg $noWrite
} {1 {can't set "noWrite": trace failed} {d b c}}

test lset-5.2 {lset, not compiled, 3 args, can't set variable} testevalex {
    list [catch {
	testevalex {lset noWrite [list 0] d}
    } msg] $msg $noWrite
} {1 {can't set "noWrite": trace failed} {d b c}}

test lset-6.1 {lset, not compiled, 3 args, 1-d list basics} testevalex {
    set a {x y z}
    list [testevalex {lset a 0 a}] $a
} {{a y z} {a y z}}

test lset-6.2 {lset, not compiled, 3 args, 1-d list basics} testevalex {
    set a {x y z}
    list [testevalex {lset a [list 0] a}] $a
} {{a y z} {a y z}}

test lset-6.3 {lset, not compiled, 1-d list basics} testevalex {
    set a {x y z}


    list [testevalex {lset a 2 a}] $a
} {{x y a} {x y a}}

test lset-6.4 {lset, not compiled, 1-d list basics} testevalex {
    set a {x y z}
    list [testevalex {lset a [list 2] a}] $a
} {{x y a} {x y a}}

test lset-6.5 {lset, not compiled, 1-d list basics} testevalex {
    set a {x y z}
    list [testevalex {lset a end a}] $a
} {{x y a} {x y a}}

test lset-6.6 {lset, not compiled, 1-d list basics} testevalex {
    set a {x y z}
    list [testevalex {lset a [list end] a}] $a
} {{x y a} {x y a}}

test lset-6.7 {lset, not compiled, 1-d list basics} testevalex {
    set a {x y z}
    list [testevalex {lset a end-0 a}] $a
} {{x y a} {x y a}}

test lset-6.8 {lset, not compiled, 1-d list basics} testevalex {
    set a {x y z}
    list [testevalex {lset a [list end-0] a}] $a
} {{x y a} {x y a}}

test lset-6.9 {lset, not compiled, 1-d list basics} testevalex {
    set a {x y z}
    list [testevalex {lset a end-2 a}] $a
} {{a y z} {a y z}}

test lset-6.10 {lset, not compiled, 1-d list basics} testevalex {
    set a {x y z}
    list [testevalex {lset a [list end-2] a}] $a
} {{a y z} {a y z}}

test lset-7.1 {lset, not compiled, data sharing} testevalex {
    set a 0
    list [testevalex {lset a $a {gag me}}] $a
} {{{gag me}} {{gag me}}}

test lset-7.2 {lset, not compiled, data sharing} testevalex {
    set a [list 0]
    list [testevalex {lset a $a {gag me}}] $a
} {{{gag me}} {{gag me}}}

test lset-7.3 {lset, not compiled, data sharing} testevalex {
    set a {x y}
    list [testevalex {lset a 0 $a}] $a
} {{{x y} y} {{x y} y}}

test lset-7.4 {lset, not compiled, data sharing} testevalex {
    set a {x y}
    list [testevalex {lset a [list 0] $a}] $a
} {{{x y} y} {{x y} y}}

test lset-7.5 {lset, not compiled, data sharing} testevalex {
    set n 0
    set a {x y}
    list [testevalex {lset a $n $n}] $a $n
} {{0 y} {0 y} 0}

test lset-7.6 {lset, not compiled, data sharing} testevalex {
    set n [list 0]
    set a {x y}
    list [testevalex {lset a $n $n}] $a $n
} {{0 y} {0 y} 0}

test lset-7.7 {lset, not compiled, data sharing} testevalex {
    set n 0
    set a [list $n $n]
    list [testevalex {lset a $n 1}] $a $n
} {{1 0} {1 0} 0}

test lset-7.8 {lset, not compiled, data sharing} testevalex {
    set n [list 0]
    set a [list $n $n]
    list [testevalex {lset a $n 1}] $a $n
} {{1 0} {1 0} 0}

test lset-7.9 {lset, not compiled, data sharing} testevalex {
    set a 0
    list [testevalex {lset a $a $a}] $a
} {0 0}

test lset-7.10 {lset, not compiled, data sharing} testevalex {
    set a [list 0]
    list [testevalex {lset a $a $a}] $a
} {0 0}

test lset-8.1 {lset, not compiled, malformed sublist} testevalex {
    set a [list "a \{" b]
    list [catch {testevalex {lset a 0 1 c}} msg] $msg
} {1 {unmatched open brace in list}}

test lset-8.2 {lset, not compiled, malformed sublist} testevalex {
    set a [list "a \{" b]
    list [catch {testevalex {lset a {0 1} c}} msg] $msg
} {1 {unmatched open brace in list}}

test lset-8.3 {lset, not compiled, bad second index} testevalex {
    set a {{b c} {d e}}
    list [catch {testevalex {lset a 0 2a2 f}} msg] $msg
} {1 {bad index "2a2": must be integer or end?-integer?}}

test lset-8.4 {lset, not compiled, bad second index} testevalex {
    set a {{b c} {d e}}
    list [catch {testevalex {lset a {0 2a2} f}} msg] $msg
} {1 {bad index "2a2": must be integer or end?-integer?}}

test lset-8.5 {lset, not compiled, second index out of range} testevalex {
    set a {{b c} {d e} {f g}}
    list [catch {testevalex {lset a 2 -1 h}} msg] $msg
} {1 {list index out of range}}

test lset-8.6 {lset, not compiled, second index out of range} testevalex {
    set a {{b c} {d e} {f g}}


    list [catch {testevalex {lset a {2 -1} h}} msg] $msg
} {1 {list index out of range}}

test lset-8.7 {lset, not compiled, second index out of range} testevalex {
    set a {{b c} {d e} {f g}}
    list [catch {testevalex {lset a 2 2 h}} msg] $msg
} {1 {list index out of range}}

test lset-8.8 {lset, not compiled, second index out of range} testevalex {
    set a {{b c} {d e} {f g}}
    list [catch {testevalex {lset a {2 2} h}} msg] $msg
} {1 {list index out of range}}

test lset-8.9 {lset, not compiled, second index out of range} testevalex {
    set a {{b c} {d e} {f g}}
    list [catch {testevalex {lset a 2 end--1 h}} msg] $msg
} {1 {list index out of range}}

test lset-8.10 {lset, not compiled, second index out of range} testevalex {
    set a {{b c} {d e} {f g}}
    list [catch {testevalex {lset a {2 end--1} h}} msg] $msg
} {1 {list index out of range}}

test lset-8.11 {lset, not compiled, second index out of range} testevalex {
    set a {{b c} {d e} {f g}}
    list [catch {testevalex {lset a 2 end-2 h}} msg] $msg
} {1 {list index out of range}}

test lset-8.12 {lset, not compiled, second index out of range} testevalex {
    set a {{b c} {d e} {f g}}
    list [catch {testevalex {lset a {2 end-2} h}} msg] $msg
} {1 {list index out of range}}

test lset-9.1 {lset, not compiled, entire variable} testevalex {
    set a x
    list [testevalex {lset a y}] $a
} {y y}

test lset-9.2 {lset, not compiled, entire variable} testevalex {
    set a x
    list [testevalex {lset a {} y}] $a
} {y y}

test lset-10.1 {lset, not compiled, shared data} testevalex {
    set row {p q}
    set a [list $row $row]
    list [testevalex {lset a 0 0 x}] $a
} {{{x q} {p q}} {{x q} {p q}}}

test lset-10.2 {lset, not compiled, shared data} testevalex {
    set row {p q}
    set a [list $row $row]
    list [testevalex {lset a {0 0} x}] $a
} {{{x q} {p q}} {{x q} {p q}}}

test lset-11.1 {lset, not compiled, 2-d basics} testevalex {
    set a {{b c} {d e}}
    list [testevalex {lset a 0 0 f}] $a
} {{{f c} {d e}} {{f c} {d e}}}

test lset-11.2 {lset, not compiled, 2-d basics} testevalex {
    set a {{b c} {d e}}
    list [testevalex {lset a {0 0} f}] $a
} {{{f c} {d e}} {{f c} {d e}}}

test lset-11.3 {lset, not compiled, 2-d basics} testevalex {
    set a {{b c} {d e}}
    list [testevalex {lset a 0 1 f}] $a
} {{{b f} {d e}} {{b f} {d e}}}

test lset-11.4 {lset, not compiled, 2-d basics} testevalex {
    set a {{b c} {d e}}


    list [testevalex {lset a {0 1} f}] $a
} {{{b f} {d e}} {{b f} {d e}}}

test lset-11.5 {lset, not compiled, 2-d basics} testevalex {
    set a {{b c} {d e}}
    list [testevalex {lset a 1 0 f}] $a
} {{{b c} {f e}} {{b c} {f e}}}

test lset-11.6 {lset, not compiled, 2-d basics} testevalex {
    set a {{b c} {d e}}
    list [testevalex {lset a {1 0} f}] $a
} {{{b c} {f e}} {{b c} {f e}}}

test lset-11.7 {lset, not compiled, 2-d basics} testevalex {
    set a {{b c} {d e}}
    list [testevalex {lset a 1 1 f}] $a
} {{{b c} {d f}} {{b c} {d f}}}

test lset-11.8 {lset, not compiled, 2-d basics} testevalex {
    set a {{b c} {d e}}
    list [testevalex {lset a {1 1} f}] $a
} {{{b c} {d f}} {{b c} {d f}}}

test lset-12.0 {lset, not compiled, typical sharing pattern} testevalex {
    set zero 0
    set row [list $zero $zero $zero $zero]
    set ident [list $row $row $row $row]
    for { set i 0 } { $i < 4 } { incr i } {
	testevalex {lset ident $i $i 1}
    }
    set ident
} {{1 0 0 0} {0 1 0 0} {0 0 1 0} {0 0 0 1}}

test lset-13.0 {lset, not compiled, shimmering hell} testevalex {
    set a 0
    list [testevalex {lset a $a $a $a $a {gag me}}] $a
} {{{{{{gag me}}}}} {{{{{gag me}}}}}}

test lset-13.1 {lset, not compiled, shimmering hell} testevalex {
    set a [list 0]
    list [testevalex {lset a $a $a $a $a {gag me}}] $a
} {{{{{{gag me}}}}} {{{{{gag me}}}}}}

test lset-13.2 {lset, not compiled, shimmering hell} testevalex {
    set a [list 0 0 0 0]
    list [testevalex {lset a $a {gag me}}] $a
} {{{{{{gag me}}}} 0 0 0} {{{{{gag me}}}} 0 0 0}}

test lset-14.1 {lset, not compiled, list args, is string rep preserved?} testevalex {
    set a { { 1 2 } { 3 4 } }
    catch { testevalex {lset a {1 5} 5} }
    list $a [lindex $a 1]
} "{ { 1 2 } { 3 4 } } { 3 4 }"

test lset-14.2 {lset, not compiled, flat args, is string rep preserved?} testevalex {
    set a { { 1 2 } { 3 4 } }
    catch { testevalex {lset a 1 5 5} }
    list $a [lindex $a 1]
} "{ { 1 2 } { 3 4 } } { 3 4 }"

catch {unset noRead}
catch {unset noWrite}
catch {rename failTrace {}}
catch {unset ::x}
Changes to tests/misc.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Copyright (c) 1992-1993 The Regents of the University of California.
# Copyright (c) 1994-1996 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.
#
# RCS: @(#) $Id: misc.test,v 1.6 2003/02/16 01:36:32 msofer Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

test misc-1.1 {error in variable ref. in command in array reference} {







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Copyright (c) 1992-1993 The Regents of the University of California.
# Copyright (c) 1994-1996 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.
#
# RCS: @(#) $Id: misc.test,v 1.6.4.1 2004/02/07 05:48:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

test misc-1.1 {error in variable ref. in command in array reference} {
61
62
63
64
65
66
67




68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
	# this is a bogus comment
	# this is a bogus comment
	# this is a bogus comment
	# this is a ..."
    (compiling body of proc "tstProc", line 4)
    invoked from within
"tstProc"}]





# cleanup
::tcltest::cleanupTests
return



















>
>
>
>




<
<
<
<
<
<
<
<
<
<
<
<
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75












	# this is a bogus comment
	# this is a bogus comment
	# this is a bogus comment
	# this is a ..."
    (compiling body of proc "tstProc", line 4)
    invoked from within
"tstProc"}]

for {set i 1} {$i<300} {incr i} {
    test misc-2.$i {hash table with sys-alloc} "testhashsystemhash $i" OK
}

# cleanup
::tcltest::cleanupTests
return












Changes to tests/msgcat.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# Note that after running these tests, entries will be left behind in the
# message catalogs for locales foo, foo_BAR, and foo_BAR_baz.
#
# RCS: @(#) $Id: msgcat.test,v 1.12 2003/03/26 22:55:44 dgp Exp $

package require Tcl 8.2
if {[catch {package require tcltest 2}]} {
    puts stderr "Skipping tests in [info script].  tcltest 2 required."
    return
}
if {[catch {package require msgcat 1.3}]} {
    puts stderr "Skipping tests in [info script].  No msgcat 1.3 found to test."
    return
}

namespace eval ::msgcat::test {
    namespace import ::msgcat::*
    namespace import ::tcltest::test
    namespace import ::tcltest::cleanupTests







|






|
|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# Note that after running these tests, entries will be left behind in the
# message catalogs for locales foo, foo_BAR, and foo_BAR_baz.
#
# RCS: @(#) $Id: msgcat.test,v 1.12.2.1 2004/02/07 05:48:03 dgp Exp $

package require Tcl 8.2
if {[catch {package require tcltest 2}]} {
    puts stderr "Skipping tests in [info script].  tcltest 2 required."
    return
}
if {[catch {package require msgcat 1.4}]} {
    puts stderr "Skipping tests in [info script].  No msgcat 1.4 found to test."
    return
}

namespace eval ::msgcat::test {
    namespace import ::msgcat::*
    namespace import ::tcltest::test
    namespace import ::tcltest::cleanupTests
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
    test msgcat-1.5 {mcpreferences, single element} -setup {
	variable locale [mclocale]
	mclocale en
    } -cleanup {
	mclocale $locale
    } -body {
	mcpreferences
    } -result en

    test msgcat-1.6 {mclocale set, two elements} -setup {
	variable locale [mclocale]
    } -cleanup {
	mclocale $locale
    } -body {
	mclocale en_US







|







107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
    test msgcat-1.5 {mcpreferences, single element} -setup {
	variable locale [mclocale]
	mclocale en
    } -cleanup {
	mclocale $locale
    } -body {
	mcpreferences
    } -result {en {}}

    test msgcat-1.6 {mclocale set, two elements} -setup {
	variable locale [mclocale]
    } -cleanup {
	mclocale $locale
    } -body {
	mclocale en_US
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
    test msgcat-1.8 {mcpreferences, two elements} -setup {
	variable locale [mclocale]
	mclocale en_US
    } -cleanup {
	mclocale $locale
    } -body {
	mcpreferences
    } -result {en_us en}

    test msgcat-1.9 {mclocale set, three elements} -setup {
	variable locale [mclocale]
    } -cleanup {
	mclocale $locale
    } -body {
	mclocale en_US_funky







|







133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
    test msgcat-1.8 {mcpreferences, two elements} -setup {
	variable locale [mclocale]
	mclocale en_US
    } -cleanup {
	mclocale $locale
    } -body {
	mcpreferences
    } -result {en_us en {}}

    test msgcat-1.9 {mclocale set, three elements} -setup {
	variable locale [mclocale]
    } -cleanup {
	mclocale $locale
    } -body {
	mclocale en_US_funky
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
    test msgcat-1.11 {mcpreferences, three elements} -setup {
	variable locale [mclocale]
	mclocale en_US_funky
    } -cleanup {
	mclocale $locale
    } -body {
	mcpreferences
    } -result {en_us_funky en_us en}

    # Tests msgcat-2.*: [mcset], [mcmset], namespace partitioning

    test msgcat-2.1 {mcset, global scope} {
	namespace eval :: ::msgcat::mcset  foo_BAR text1 text2
    } {text2}








|







159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
    test msgcat-1.11 {mcpreferences, three elements} -setup {
	variable locale [mclocale]
	mclocale en_US_funky
    } -cleanup {
	mclocale $locale
    } -body {
	mcpreferences
    } -result {en_us_funky en_us en {}}

    # Tests msgcat-2.*: [mcset], [mcmset], namespace partitioning

    test msgcat-2.1 {mcset, global scope} {
	namespace eval :: ::msgcat::mcset  foo_BAR text1 text2
    } {text2}

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

    # Tests msgcat-3.*: [mcset], [mc], catalog "inheritance"
    #
    # Test mcset and mc, ensuring that more specific locales
    # (e.g. en_UK) will search less specific locales
    # (e.g. en) for translation strings.
    #
    # Do this for the 12 permutations of
    #     locales: {foo foo_BAR foo_BAR_baz}
    #     strings: {ov1 ov2 ov3 ov4}

    #     locale foo         defines ov1, ov2, ov3
    #     locale foo_BAR     defines      ov2, ov3
    #     locale foo_BAR_BAZ defines           ov3
    #     (ov4 is defined in none)
    # So,
    #     ov3 should be resolved in foo, foo_BAR, foo_BAR_baz
    #     ov2 should be resolved in foo, foo_BAR
    #     ov2 should resolve to foo_BAR in foo_BAR_baz
    #     ov1 should be resolved in foo
    #     ov1 should resolve to foo in foo_BAR, foo_BAR_baz
    #     ov4 should be resolved in none, and call mcunknown
    #
    variable count 2
    variable result
    array set result {

	foo,ov1 ov1_foo foo,ov2 ov2_foo foo,ov3 ov3_foo foo,ov4 ov4
	foo_BAR,ov1 ov1_foo foo_BAR,ov2 ov2_foo_BAR foo_BAR,ov3 ov3_foo_BAR


	foo_BAR,ov4 ov4 foo_BAR_baz,ov1 ov1_foo foo_BAR_baz,ov2 ov2_foo_BAR
	foo_BAR_baz,ov3 ov3_foo_BAR_baz foo_BAR_baz,ov4 ov4
    }
    variable loc
    variable string
    foreach loc {foo foo_BAR foo_BAR_baz} {
	foreach string {ov1 ov2 ov3 ov4} {
	    test msgcat-3.$count {mcset, overlap} -setup {




		mcset foo ov1 ov1_foo
		mcset foo ov2 ov2_foo
		mcset foo ov3 ov3_foo
		mcset foo_BAR ov2 ov2_foo_BAR
		mcset foo_BAR ov3 ov3_foo_BAR
		mcset foo_BAR_baz ov3 ov3_foo_BAR_baz
		variable locale [mclocale]







|

|
>
|
|
|












>
|
|
>
>
|





|

>
>
>
>







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

    # Tests msgcat-3.*: [mcset], [mc], catalog "inheritance"
    #
    # Test mcset and mc, ensuring that more specific locales
    # (e.g. en_UK) will search less specific locales
    # (e.g. en) for translation strings.
    #
    # Do this for the 15 permutations of
    #     locales: {foo foo_BAR foo_BAR_baz}
    #     strings: {ov0 ov1 ov2 ov3 ov4}
    #	  locale ROOT        defines ov0, ov1, ov2, ov3
    #     locale foo         defines      ov1, ov2, ov3
    #     locale foo_BAR     defines           ov2, ov3
    #     locale foo_BAR_BAZ defines                ov3
    #     (ov4 is defined in none)
    # So,
    #     ov3 should be resolved in foo, foo_BAR, foo_BAR_baz
    #     ov2 should be resolved in foo, foo_BAR
    #     ov2 should resolve to foo_BAR in foo_BAR_baz
    #     ov1 should be resolved in foo
    #     ov1 should resolve to foo in foo_BAR, foo_BAR_baz
    #     ov4 should be resolved in none, and call mcunknown
    #
    variable count 2
    variable result
    array set result {
	foo,ov0 ov0_ROOT foo,ov1 ov1_foo foo,ov2 ov2_foo 
        foo,ov3 ov3_foo foo,ov4 ov4
	foo_BAR,ov0 ov0_ROOT foo_BAR,ov1 ov1_foo foo_BAR,ov2 ov2_foo_BAR 
        foo_BAR,ov3 ov3_foo_BAR	foo_BAR,ov4 ov4 
        foo_BAR_baz,ov0 ov0_ROOT foo_BAR_baz,ov1 ov1_foo 
        foo_BAR_baz,ov2 ov2_foo_BAR
	foo_BAR_baz,ov3 ov3_foo_BAR_baz foo_BAR_baz,ov4 ov4
    }
    variable loc
    variable string
    foreach loc {foo foo_BAR foo_BAR_baz} {
	foreach string {ov0 ov1 ov2 ov3 ov4} {
	    test msgcat-3.$count {mcset, overlap} -setup {
		mcset {} ov0 ov0_ROOT
		mcset {} ov1 ov1_ROOT
		mcset {} ov2 ov2_ROOT
		mcset {} ov3 ov3_ROOT
		mcset foo ov1 ov1_foo
		mcset foo ov2 ov2_foo
		mcset foo ov3 ov3_foo
		mcset foo_BAR ov2 ov2_foo_BAR
		mcset foo_BAR ov3 ov3_foo_BAR
		mcset foo_BAR_baz ov3 ov3_foo_BAR_baz
		variable locale [mclocale]
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
	rename SavedMcunknown ::msgcat::mcunknown
    } -body {
	mc unk2
    } -result unknown:foo:unk2:[info level]

    # Tests msgcat-5.*: [mcload]

    variable locales {foo foo_BAR foo_BAR_baz}
    makeDirectory msgdir
    foreach loc $locales {
	makeFile "::msgcat::mcset $loc abc abc-$loc" \


		[string tolower [file join msgdir $loc.msg]]


    }
    variable count 1
    foreach loc {foo foo_BAR foo_BAR_baz} {
	test msgcat-5.$count {mcload} -setup {
	    variable locale [mclocale]
	    mclocale $loc
	} -cleanup {
	    mclocale $locale
	} -body {
	    mcload [file join [temporaryDirectory] msgdir]
	} -result $count
	incr count
    }

    # Even though foo_BAR_notexist does not exist,
    # foo_BAR and foo should be loaded.
	test msgcat-5.4 {mcload} -setup {
	    variable locale [mclocale]
	    mclocale foo_BAR_notexist
	} -cleanup {
	    mclocale $locale
	} -body {
	    mcload [file join [temporaryDirectory] msgdir]
	} -result 2

	test msgcat-5.5 {mcload} -setup {
	    variable locale [mclocale]
	    mclocale no_FI_notexist
	} -cleanup {
	    mclocale $locale
	} -body {
	    mcload [file join [temporaryDirectory] msgdir]
	} -result 0

	test msgcat-5.6 {mcload} -setup {
	    variable locale [mclocale]
	    mclocale foo

	} -cleanup {
	    mclocale $locale
	} -body {
	    mc abc
	} -result abc-foo

	test msgcat-5.7 {mcload} -setup {
	    variable locale [mclocale]
	    mclocale foo_BAR

	} -cleanup {
	    mclocale $locale
	} -body {
	    mc abc
	} -result abc-foo_BAR

	test msgcat-5.8 {mcload} -setup {
	    variable locale [mclocale]
	    mclocale foo_BAR_baz

	} -cleanup {
	    mclocale $locale
	} -body {
	    mc abc
	} -result abc-foo_BAR_baz

	test msgcat-5.9 {mcload} -setup {










	    rename ::msgcat::mcunknown SavedMcunknown
	    proc ::msgcat::mcunknown {dom s} {
		return unknown:$dom:$s
	    }
	    variable locale [mclocale]
	    mclocale no_FI_notexist

	} -cleanup {
	    mclocale $locale
	    rename ::msgcat::mcunknown {}
	    rename SavedMcunknown ::msgcat::mcunknown
	} -body {
	    mc abc
	} -result unknown:no_fi_notexist:abc


    foreach loc $locales {



	removeFile [string tolower [file join msgdir $loc.msg]]


    }
    removeDirectory msgdir

    # Tests msgcat-6.*: [mcset], [mc] namespace inheritance
#
# Test mcset and mc, ensuring that resolution for messages
# proceeds from the current ns to its parent and so on to the 







|
|

|
>
>
|
>
>









|
|




|






|
|







|
|




>









>









>







>
>
>
>
>
>
>
>
>
>






>





|
|

<

>
>
>
|
>
>







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
	rename SavedMcunknown ::msgcat::mcunknown
    } -body {
	mc unk2
    } -result unknown:foo:unk2:[info level]

    # Tests msgcat-5.*: [mcload]

    variable locales {{} foo foo_BAR foo_BAR_baz}
    set msgdir [makeDirectory msgdir]
    foreach loc $locales {
	if { $loc eq {} } {
	    set msg ROOT
        } else {
	    set msg [string tolower $loc]
	}
	makeFile [list ::msgcat::mcset $loc abc abc-$loc] $msg.msg msgdir
    }
    variable count 1
    foreach loc {foo foo_BAR foo_BAR_baz} {
	test msgcat-5.$count {mcload} -setup {
	    variable locale [mclocale]
	    mclocale $loc
	} -cleanup {
	    mclocale $locale
	} -body {
	    mcload $msgdir
	} -result [expr { $count+1 }]
	incr count
    }

    # Even though foo_BAR_notexist does not exist,
    # foo_BAR, foo and the root should be loaded.
	test msgcat-5.4 {mcload} -setup {
	    variable locale [mclocale]
	    mclocale foo_BAR_notexist
	} -cleanup {
	    mclocale $locale
	} -body {
	    mcload $msgdir
	} -result 3

	test msgcat-5.5 {mcload} -setup {
	    variable locale [mclocale]
	    mclocale no_FI_notexist
	} -cleanup {
	    mclocale $locale
	} -body {
	    mcload $msgdir
	} -result 1

	test msgcat-5.6 {mcload} -setup {
	    variable locale [mclocale]
	    mclocale foo
	    mcload $msgdir
	} -cleanup {
	    mclocale $locale
	} -body {
	    mc abc
	} -result abc-foo

	test msgcat-5.7 {mcload} -setup {
	    variable locale [mclocale]
	    mclocale foo_BAR
	    mcload $msgdir
	} -cleanup {
	    mclocale $locale
	} -body {
	    mc abc
	} -result abc-foo_BAR

	test msgcat-5.8 {mcload} -setup {
	    variable locale [mclocale]
	    mclocale foo_BAR_baz
	    mcload $msgdir
	} -cleanup {
	    mclocale $locale
	} -body {
	    mc abc
	} -result abc-foo_BAR_baz

	test msgcat-5.9 {mcload} -setup {
	    variable locale [mclocale]
	    mclocale no_FI_notexist
	    mcload $msgdir
	} -cleanup {
	    mclocale $locale
	} -body {
	    mc abc
	} -result abc-

	test msgcat-5.10 {mcload} -setup {
	    rename ::msgcat::mcunknown SavedMcunknown
	    proc ::msgcat::mcunknown {dom s} {
		return unknown:$dom:$s
	    }
	    variable locale [mclocale]
	    mclocale no_FI_notexist
	    mcload $msgdir
	} -cleanup {
	    mclocale $locale
	    rename ::msgcat::mcunknown {}
	    rename SavedMcunknown ::msgcat::mcunknown
	} -body {
	    mc def
	} -result unknown:no_fi_notexist:def


    foreach loc $locales {
	if { $loc eq {} } {
	    set msg ROOT
        } else {
	    set msg [string tolower $loc]
	}
	removeFile $msg.msg msgdir
    }
    removeDirectory msgdir

    # Tests msgcat-6.*: [mcset], [mc] namespace inheritance
#
# Test mcset and mc, ensuring that resolution for messages
# proceeds from the current ns to its parent and so on to the 
Changes to tests/namespace-old.test.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# Copyright (c) 1997 Sun Microsystems, Inc.
# Copyright (c) 1997 Lucent Technologies
# 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.
#
# RCS: @(#) $Id: namespace-old.test,v 1.6 2001/04/07 02:11:19 msofer Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

# Clear out any namespaces called test_ns_*
catch {eval namespace delete [namespace children :: test_ns_*]}

test namespace-old-1.1 {usage for "namespace" command} {
    list [catch {namespace} msg] $msg
} {1 {wrong # args: should be "namespace subcommand ?arg ...?"}}

test namespace-old-1.2 {global namespace's name is "::" or {}} {
    list [namespace current] [namespace eval {} {namespace current}]







|







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# Copyright (c) 1997 Sun Microsystems, Inc.
# Copyright (c) 1997 Lucent Technologies
# 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.
#
# RCS: @(#) $Id: namespace-old.test,v 1.6.20.1 2004/02/07 05:48:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

# Clear out any namespaces called test_ns_*
catch {namespace delete {expand}[namespace children :: test_ns_*]}

test namespace-old-1.1 {usage for "namespace" command} {
    list [catch {namespace} msg] $msg
} {1 {wrong # args: should be "namespace subcommand ?arg ...?"}}

test namespace-old-1.2 {global namespace's name is "::" or {}} {
    list [namespace current] [namespace eval {} {namespace current}]
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
    }
    list [catch $cmd msg] $msg
} {1 {unknown namespace "ns*" in namespace delete command}}

test namespace-old-4.4 {command "namespace delete" handles multiple args} {
    set cmd {
        namespace eval test_ns_delete {
            eval namespace delete \
                [namespace children [namespace current] ns?]
        }
    }
    list [catch $cmd msg] $msg [namespace children test_ns_delete]
} {0 {} ::test_ns_delete::another}

# -----------------------------------------------------------------------
# TEST: namespace hierarchy







|
|







247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
    }
    list [catch $cmd msg] $msg
} {1 {unknown namespace "ns*" in namespace delete command}}

test namespace-old-4.4 {command "namespace delete" handles multiple args} {
    set cmd {
        namespace eval test_ns_delete {
            namespace delete \
                {expand}[namespace children [namespace current] ns?]
        }
    }
    list [catch $cmd msg] $msg [namespace children test_ns_delete]
} {0 {} ::test_ns_delete::another}

# -----------------------------------------------------------------------
# TEST: namespace hierarchy
Changes to tests/namespace.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
# Functionality covered: this file contains a collection of tests for the
# procedures in tclNamesp.c that implement Tcl's basic support for
# namespaces. Other namespace-related tests appear in variable.test.
#
# 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-2000 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: namespace.test,v 1.21.4.1 2003/10/16 02:28:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# Clear out any namespaces called test_ns_*
catch {eval namespace delete [namespace children :: test_ns_*]}

test namespace-1.1 {TclInitNamespaces, GetNamespaceFromObj, NamespaceChildrenCmd} {
    namespace children :: test_ns_*
} {}

catch {unset l}
test namespace-2.1 {Tcl_GetCurrentNamespace} {













|







|







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
# Functionality covered: this file contains a collection of tests for the
# procedures in tclNamesp.c that implement Tcl's basic support for
# namespaces. Other namespace-related tests appear in variable.test.
#
# 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-2000 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: namespace.test,v 1.21.4.2 2004/02/07 05:48:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# Clear out any namespaces called test_ns_*
catch {namespace delete {expand}[namespace children :: test_ns_*]}

test namespace-1.1 {TclInitNamespaces, GetNamespaceFromObj, NamespaceChildrenCmd} {
    namespace children :: test_ns_*
} {}

catch {unset l}
test namespace-2.1 {Tcl_GetCurrentNamespace} {
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
    proc test_ns_1::r {} {
        set a 123
    }
    test_ns_1::r   ;# pushes then pop's r's frame
} {123}

test namespace-6.1 {Tcl_CreateNamespace} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [lsort [namespace children :: test_ns_*]] \
        [namespace eval test_ns_1 {namespace current}] \
	[namespace eval test_ns_2 {namespace current}] \
	[namespace eval ::test_ns_3 {namespace current}] \
	[namespace eval ::test_ns_4 \
            {namespace eval foo {namespace current}}] \
	[namespace eval ::test_ns_5 \
            {namespace eval ::test_ns_6 {namespace current}}] \
        [lsort [namespace children :: test_ns_*]]
} {{} ::test_ns_1 ::test_ns_2 ::test_ns_3 ::test_ns_4::foo ::test_ns_6 {::test_ns_1 ::test_ns_2 ::test_ns_3 ::test_ns_4 ::test_ns_5 ::test_ns_6}}
test namespace-6.2 {Tcl_CreateNamespace, odd number of :'s in name is okay} {
    list [namespace eval :::test_ns_1::::foo {namespace current}] \
         [namespace eval test_ns_2:::::foo {namespace current}]
} {::test_ns_1::foo ::test_ns_2::foo}
test namespace-6.3 {Tcl_CreateNamespace, trailing ::s in ns name are ignored} {
    list [catch {namespace eval test_ns_7::: {namespace current}} msg] $msg 
} {0 ::test_ns_7}
test namespace-6.4 {Tcl_CreateNamespace, trailing ::s in ns name are ignored} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1:: {
        namespace eval test_ns_2:: {}
        namespace eval test_ns_3:: {}
    }
    lsort [namespace children ::test_ns_1]
} [lsort {::test_ns_1::test_ns_2 ::test_ns_1::test_ns_3}]
test namespace-6.5 {Tcl_CreateNamespace, relative ns names now only looked up in current ns} {
    set trigger {
        namespace eval test_ns_2 {namespace current}
    }
    set l {}
    lappend l [namespace eval test_ns_1 $trigger]
    namespace eval test_ns_1::test_ns_2 {}
    lappend l [namespace eval test_ns_1 $trigger]
} {::test_ns_1::test_ns_2 ::test_ns_1::test_ns_2}

test namespace-7.1 {Tcl_DeleteNamespace, active call frames in ns} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        proc p {} {
            namespace delete [namespace current]
            return [namespace current]
        }
    }
    list [test_ns_1::p] [catch {test_ns_1::p} msg] $msg







|


















|

















|







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
    proc test_ns_1::r {} {
        set a 123
    }
    test_ns_1::r   ;# pushes then pop's r's frame
} {123}

test namespace-6.1 {Tcl_CreateNamespace} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [lsort [namespace children :: test_ns_*]] \
        [namespace eval test_ns_1 {namespace current}] \
	[namespace eval test_ns_2 {namespace current}] \
	[namespace eval ::test_ns_3 {namespace current}] \
	[namespace eval ::test_ns_4 \
            {namespace eval foo {namespace current}}] \
	[namespace eval ::test_ns_5 \
            {namespace eval ::test_ns_6 {namespace current}}] \
        [lsort [namespace children :: test_ns_*]]
} {{} ::test_ns_1 ::test_ns_2 ::test_ns_3 ::test_ns_4::foo ::test_ns_6 {::test_ns_1 ::test_ns_2 ::test_ns_3 ::test_ns_4 ::test_ns_5 ::test_ns_6}}
test namespace-6.2 {Tcl_CreateNamespace, odd number of :'s in name is okay} {
    list [namespace eval :::test_ns_1::::foo {namespace current}] \
         [namespace eval test_ns_2:::::foo {namespace current}]
} {::test_ns_1::foo ::test_ns_2::foo}
test namespace-6.3 {Tcl_CreateNamespace, trailing ::s in ns name are ignored} {
    list [catch {namespace eval test_ns_7::: {namespace current}} msg] $msg 
} {0 ::test_ns_7}
test namespace-6.4 {Tcl_CreateNamespace, trailing ::s in ns name are ignored} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1:: {
        namespace eval test_ns_2:: {}
        namespace eval test_ns_3:: {}
    }
    lsort [namespace children ::test_ns_1]
} [lsort {::test_ns_1::test_ns_2 ::test_ns_1::test_ns_3}]
test namespace-6.5 {Tcl_CreateNamespace, relative ns names now only looked up in current ns} {
    set trigger {
        namespace eval test_ns_2 {namespace current}
    }
    set l {}
    lappend l [namespace eval test_ns_1 $trigger]
    namespace eval test_ns_1::test_ns_2 {}
    lappend l [namespace eval test_ns_1 $trigger]
} {::test_ns_1::test_ns_2 ::test_ns_1::test_ns_2}

test namespace-7.1 {Tcl_DeleteNamespace, active call frames in ns} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        proc p {} {
            namespace delete [namespace current]
            return [namespace current]
        }
    }
    list [test_ns_1::p] [catch {test_ns_1::p} msg] $msg
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
    }
    list [interp eval test_interp {test_ns_2::q}] \
         [interp eval test_interp {namespace delete ::}] \
         [catch {interp eval test_interp {set a 123}} msg] $msg \
         [interp delete test_interp]
} {{::test_ns_1 27} {} 1 {invalid command name "set"} {}}
test namespace-8.2 {TclTeardownNamespace, remove deleted ns from parent} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1::test_ns_2::test_ns_3a {proc p {} {}}
    namespace eval test_ns_1::test_ns_2::test_ns_3b {proc q {} {}}
    list [namespace children test_ns_1] \
         [namespace delete test_ns_1::test_ns_2] \
         [namespace children test_ns_1]
} {::test_ns_1::test_ns_2 {} {}}
test namespace-8.3 {TclTeardownNamespace, delete child namespaces} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1::test_ns_2::test_ns_3a {proc p {} {}}
    namespace eval test_ns_1::test_ns_2::test_ns_3b {proc q {} {}}
    list [namespace children test_ns_1] \
         [namespace delete test_ns_1::test_ns_2] \
         [namespace children test_ns_1] \
         [catch {namespace children test_ns_1::test_ns_2} msg] $msg \
         [info commands test_ns_1::test_ns_2::test_ns_3a::*]
} {::test_ns_1::test_ns_2 {} {} 1 {unknown namespace "test_ns_1::test_ns_2" in namespace children command} {}}
test namespace-8.4 {TclTeardownNamespace, cmds imported from deleted ns go away} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_export {
        namespace export cmd1 cmd2
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_import {
        namespace import ::test_ns_export::*
        proc p {} {return foo}
    }
    list [lsort [info commands test_ns_import::*]] \
         [namespace delete test_ns_export] \
         [info commands test_ns_import::*]
} [list [lsort {::test_ns_import::p ::test_ns_import::cmd1 ::test_ns_import::cmd2}] {} ::test_ns_import::p]

test namespace-9.1 {Tcl_Import, empty import pattern} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [catch {namespace eval test_ns_import {namespace import {}}} msg] $msg
} {1 {empty import pattern}}
test namespace-9.2 {Tcl_Import, unknown namespace in import pattern} {
    list [catch {namespace eval test_ns_import {namespace import fred::x}} msg] $msg
} {1 {unknown namespace in import pattern "fred::x"}}
test namespace-9.3 {Tcl_Import, import ns == export ns} {
    list [catch {namespace eval test_ns_import {namespace import ::test_ns_import::puts}} msg] $msg
} {1 {import pattern "::test_ns_import::puts" tries to import from namespace "test_ns_import" into itself}}
test namespace-9.4 {Tcl_Import, simple import} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_export {
        namespace export cmd1
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_import {
        namespace import ::test_ns_export::*







|







|









|















|









|







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
    }
    list [interp eval test_interp {test_ns_2::q}] \
         [interp eval test_interp {namespace delete ::}] \
         [catch {interp eval test_interp {set a 123}} msg] $msg \
         [interp delete test_interp]
} {{::test_ns_1 27} {} 1 {invalid command name "set"} {}}
test namespace-8.2 {TclTeardownNamespace, remove deleted ns from parent} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1::test_ns_2::test_ns_3a {proc p {} {}}
    namespace eval test_ns_1::test_ns_2::test_ns_3b {proc q {} {}}
    list [namespace children test_ns_1] \
         [namespace delete test_ns_1::test_ns_2] \
         [namespace children test_ns_1]
} {::test_ns_1::test_ns_2 {} {}}
test namespace-8.3 {TclTeardownNamespace, delete child namespaces} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1::test_ns_2::test_ns_3a {proc p {} {}}
    namespace eval test_ns_1::test_ns_2::test_ns_3b {proc q {} {}}
    list [namespace children test_ns_1] \
         [namespace delete test_ns_1::test_ns_2] \
         [namespace children test_ns_1] \
         [catch {namespace children test_ns_1::test_ns_2} msg] $msg \
         [info commands test_ns_1::test_ns_2::test_ns_3a::*]
} {::test_ns_1::test_ns_2 {} {} 1 {unknown namespace "test_ns_1::test_ns_2" in namespace children command} {}}
test namespace-8.4 {TclTeardownNamespace, cmds imported from deleted ns go away} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_export {
        namespace export cmd1 cmd2
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_import {
        namespace import ::test_ns_export::*
        proc p {} {return foo}
    }
    list [lsort [info commands test_ns_import::*]] \
         [namespace delete test_ns_export] \
         [info commands test_ns_import::*]
} [list [lsort {::test_ns_import::p ::test_ns_import::cmd1 ::test_ns_import::cmd2}] {} ::test_ns_import::p]

test namespace-9.1 {Tcl_Import, empty import pattern} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [catch {namespace eval test_ns_import {namespace import {}}} msg] $msg
} {1 {empty import pattern}}
test namespace-9.2 {Tcl_Import, unknown namespace in import pattern} {
    list [catch {namespace eval test_ns_import {namespace import fred::x}} msg] $msg
} {1 {unknown namespace in import pattern "fred::x"}}
test namespace-9.3 {Tcl_Import, import ns == export ns} {
    list [catch {namespace eval test_ns_import {namespace import ::test_ns_import::puts}} msg] $msg
} {1 {import pattern "::test_ns_import::puts" tries to import from namespace "test_ns_import" into itself}}
test namespace-9.4 {Tcl_Import, simple import} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_export {
        namespace export cmd1
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_import {
        namespace import ::test_ns_export::*
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
test namespace-9.6 {Tcl_Import, cmd redefinition ok if allowOverwrite!=0} {
    namespace eval test_ns_import {
        namespace import -force ::test_ns_export::*
        cmd1 555
    }
} {cmd1: 555}
test namespace-9.7 {Tcl_Import, links are preserved if cmd is redefined} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_export {
        namespace export cmd1
        proc cmd1 {args} {return "cmd1: $args"}
    }
    namespace eval test_ns_import {
        namespace import -force ::test_ns_export::*
    }
    list [test_ns_import::cmd1 a b c] \
         [test_ns_export::cmd1 d e f] \
         [proc test_ns_export::cmd1 {args} {return "new1: $args"}] \
         [namespace origin test_ns_import::cmd1] \
         [namespace origin test_ns_export::cmd1] \
         [test_ns_import::cmd1 g h i] \
         [test_ns_export::cmd1 j k l]
} {{cmd1: a b c} {cmd1: d e f} {} ::test_ns_export::cmd1 ::test_ns_export::cmd1 {new1: g h i} {new1: j k l}}

test namespace-10.1 {Tcl_ForgetImport, check for valid namespaces} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [catch {namespace forget xyzzy::*} msg] $msg
} {1 {unknown namespace in namespace forget pattern "xyzzy::*"}}
test namespace-10.2 {Tcl_ForgetImport, ignores patterns that don't match} {
    namespace eval test_ns_export {
        namespace export cmd1
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}







|

















|







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
test namespace-9.6 {Tcl_Import, cmd redefinition ok if allowOverwrite!=0} {
    namespace eval test_ns_import {
        namespace import -force ::test_ns_export::*
        cmd1 555
    }
} {cmd1: 555}
test namespace-9.7 {Tcl_Import, links are preserved if cmd is redefined} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_export {
        namespace export cmd1
        proc cmd1 {args} {return "cmd1: $args"}
    }
    namespace eval test_ns_import {
        namespace import -force ::test_ns_export::*
    }
    list [test_ns_import::cmd1 a b c] \
         [test_ns_export::cmd1 d e f] \
         [proc test_ns_export::cmd1 {args} {return "new1: $args"}] \
         [namespace origin test_ns_import::cmd1] \
         [namespace origin test_ns_export::cmd1] \
         [test_ns_import::cmd1 g h i] \
         [test_ns_export::cmd1 j k l]
} {{cmd1: a b c} {cmd1: d e f} {} ::test_ns_export::cmd1 ::test_ns_export::cmd1 {new1: g h i} {new1: j k l}}

test namespace-10.1 {Tcl_ForgetImport, check for valid namespaces} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [catch {namespace forget xyzzy::*} msg] $msg
} {1 {unknown namespace in namespace forget pattern "xyzzy::*"}}
test namespace-10.2 {Tcl_ForgetImport, ignores patterns that don't match} {
    namespace eval test_ns_export {
        namespace export cmd1
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
        namespace forget ::test_ns_export::cmd1
        lappend l [info commands ::test_ns_import::*]
        lappend l [catch {cmd1 777} msg] $msg
    }
} [list [lsort {::test_ns_import::p ::test_ns_import::cmd1}] ::test_ns_import::p 1 {invalid command name "cmd1"}]

test namespace-11.1 {TclGetOriginalCommand, check if not imported cmd} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_export {
        namespace export cmd1
        proc cmd1 {args} {return "cmd1: $args"}
    }
    list [namespace origin set] [namespace origin test_ns_export::cmd1]
} {::set ::test_ns_export::cmd1}
test namespace-11.2 {TclGetOriginalCommand, directly imported cmd} {







|







267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
        namespace forget ::test_ns_export::cmd1
        lappend l [info commands ::test_ns_import::*]
        lappend l [catch {cmd1 777} msg] $msg
    }
} [list [lsort {::test_ns_import::p ::test_ns_import::cmd1}] ::test_ns_import::p 1 {invalid command name "cmd1"}]

test namespace-11.1 {TclGetOriginalCommand, check if not imported cmd} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_export {
        namespace export cmd1
        proc cmd1 {args} {return "cmd1: $args"}
    }
    list [namespace origin set] [namespace origin test_ns_export::cmd1]
} {::set ::test_ns_export::cmd1}
test namespace-11.2 {TclGetOriginalCommand, directly imported cmd} {
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
        namespace import ::test_ns_import1::*
        proc q {} {return [cmd1 123]}
    }
    list [test_ns_import2::q] [namespace origin test_ns_import2::cmd1]
} {{cmd1: 123} ::test_ns_export::cmd1}

test namespace-12.1 {InvokeImportedCmd} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_export {
        namespace export cmd1
        proc cmd1 {args} {namespace current}
    }
    namespace eval test_ns_import {
        namespace import ::test_ns_export::*
    }
    list [test_ns_import::cmd1]
} {::test_ns_export}

test namespace-13.1 {DeleteImportedCmd, deletes imported cmds} {
    namespace eval test_ns_import {
        set l {}
        lappend l [info commands ::test_ns_import::*]
        namespace forget ::test_ns_export::cmd1
        lappend l [info commands ::test_ns_import::*]
    }
} {::test_ns_import::cmd1 {}}

test namespace-14.1 {TclGetNamespaceForQualName, absolute names} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    variable v 10
    namespace eval test_ns_1::test_ns_2 {
        variable v 20
    }
    namespace eval test_ns_2 {
        variable v 30
    }







|




















|







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
        namespace import ::test_ns_import1::*
        proc q {} {return [cmd1 123]}
    }
    list [test_ns_import2::q] [namespace origin test_ns_import2::cmd1]
} {{cmd1: 123} ::test_ns_export::cmd1}

test namespace-12.1 {InvokeImportedCmd} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_export {
        namespace export cmd1
        proc cmd1 {args} {namespace current}
    }
    namespace eval test_ns_import {
        namespace import ::test_ns_export::*
    }
    list [test_ns_import::cmd1]
} {::test_ns_export}

test namespace-13.1 {DeleteImportedCmd, deletes imported cmds} {
    namespace eval test_ns_import {
        set l {}
        lappend l [info commands ::test_ns_import::*]
        namespace forget ::test_ns_export::cmd1
        lappend l [info commands ::test_ns_import::*]
    }
} {::test_ns_import::cmd1 {}}

test namespace-14.1 {TclGetNamespaceForQualName, absolute names} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    variable v 10
    namespace eval test_ns_1::test_ns_2 {
        variable v 20
    }
    namespace eval test_ns_2 {
        variable v 30
    }
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
    catch {rename test_ns_1::test_ns_2:: {}}
    set l {}
    lappend l [catch {test_ns_1::test_ns_2:: hello} msg] $msg
    proc test_ns_1::test_ns_2:: {args} {return "\{\}: $args"}
    lappend l [test_ns_1::test_ns_2:: hello]
} {1 {invalid command name "test_ns_1::test_ns_2::"} {{}: hello}}
test namespace-14.12 {TclGetNamespaceForQualName, extra ::s are significant for vars} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        variable {}
        set test_ns_1::(x) y
    }
    set test_ns_1::(x)
} y
test namespace-14.13 {TclGetNamespaceForQualName, namespace other than global ns can't have empty name} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [catch {namespace eval test_ns_1 {proc {} {} {}; namespace eval {} {}; {}}} msg] $msg
} {1 {can't create namespace "": only global namespace can have empty name}}

test namespace-15.1 {Tcl_FindNamespace, absolute name found} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_delete {
        namespace eval test_ns_delete2 {}
        proc cmd {args} {namespace current}
    }
    list [namespace delete ::test_ns_delete::test_ns_delete2] \
         [namespace children ::test_ns_delete]
} {{} {}}







|







|




|







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
    catch {rename test_ns_1::test_ns_2:: {}}
    set l {}
    lappend l [catch {test_ns_1::test_ns_2:: hello} msg] $msg
    proc test_ns_1::test_ns_2:: {args} {return "\{\}: $args"}
    lappend l [test_ns_1::test_ns_2:: hello]
} {1 {invalid command name "test_ns_1::test_ns_2::"} {{}: hello}}
test namespace-14.12 {TclGetNamespaceForQualName, extra ::s are significant for vars} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        variable {}
        set test_ns_1::(x) y
    }
    set test_ns_1::(x)
} y
test namespace-14.13 {TclGetNamespaceForQualName, namespace other than global ns can't have empty name} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [catch {namespace eval test_ns_1 {proc {} {} {}; namespace eval {} {}; {}}} msg] $msg
} {1 {can't create namespace "": only global namespace can have empty name}}

test namespace-15.1 {Tcl_FindNamespace, absolute name found} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_delete {
        namespace eval test_ns_delete2 {}
        proc cmd {args} {namespace current}
    }
    list [namespace delete ::test_ns_delete::test_ns_delete2] \
         [namespace children ::test_ns_delete]
} {{} {}}
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
    namespace eval test_ns_delete2 {}
    namespace eval test_ns_delete {
        list [catch {namespace delete test_ns_delete2} msg] $msg
    }
} {1 {unknown namespace "test_ns_delete2" in namespace delete command}}

test namespace-16.1 {Tcl_FindCommand, absolute name found} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        proc cmd {args} {return "[namespace current]::cmd: $args"}
        variable v "::test_ns_1::cmd"
        eval $v one
    }
} {::test_ns_1::cmd: one}
test namespace-16.2 {Tcl_FindCommand, absolute name found} {







|







430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
    namespace eval test_ns_delete2 {}
    namespace eval test_ns_delete {
        list [catch {namespace delete test_ns_delete2} msg] $msg
    }
} {1 {unknown namespace "test_ns_delete2" in namespace delete command}}

test namespace-16.1 {Tcl_FindCommand, absolute name found} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        proc cmd {args} {return "[namespace current]::cmd: $args"}
        variable v "::test_ns_1::cmd"
        eval $v one
    }
} {::test_ns_1::cmd: one}
test namespace-16.2 {Tcl_FindCommand, absolute name found} {
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
    namespace eval test_ns_1 {
       list [catch {cmd3 a b c} msg] $msg
    }
} {1 {invalid command name "cmd3"}}

catch {unset x}
test namespace-17.1 {Tcl_FindNamespaceVar, absolute name found} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    set x 314159
    namespace eval test_ns_1 {
        set ::x
    }
} {314159}
test namespace-17.2 {Tcl_FindNamespaceVar, absolute name found} {
    namespace eval test_ns_1 {







|







498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
    namespace eval test_ns_1 {
       list [catch {cmd3 a b c} msg] $msg
    }
} {1 {invalid command name "cmd3"}}

catch {unset x}
test namespace-17.1 {Tcl_FindNamespaceVar, absolute name found} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    set x 314159
    namespace eval test_ns_1 {
        set ::x
    }
} {314159}
test namespace-17.2 {Tcl_FindNamespaceVar, absolute name found} {
    namespace eval test_ns_1 {
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
    set test_ns_1::a
} {hello}
catch {unset x}

catch {unset l}
catch {rename foo {}}
test namespace-18.1 {TclResetShadowedCmdRefs, one-level check for command shadowing} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    proc foo {} {return "global foo"}
    namespace eval test_ns_1 {
        proc trigger {} {
            return [foo]
        }
    }
    set l ""







|







561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
    set test_ns_1::a
} {hello}
catch {unset x}

catch {unset l}
catch {rename foo {}}
test namespace-18.1 {TclResetShadowedCmdRefs, one-level check for command shadowing} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    proc foo {} {return "global foo"}
    namespace eval test_ns_1 {
        proc trigger {} {
            return [foo]
        }
    }
    set l ""
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
    lappend l [test_ns_1::trigger]
    set l
} {{foo in ::test_ns_2} {foo in ::test_ns_1::test_ns_2}}
catch {unset l}
catch {rename foo {}}

test namespace-19.1 {GetNamespaceFromObj, global name found} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1::test_ns_2 {}
    namespace children ::test_ns_1
} {::test_ns_1::test_ns_2}
test namespace-19.2 {GetNamespaceFromObj, relative name found} {
    namespace eval test_ns_1 {
        namespace children test_ns_2
    }







|







602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
    lappend l [test_ns_1::trigger]
    set l
} {{foo in ::test_ns_2} {foo in ::test_ns_1::test_ns_2}}
catch {unset l}
catch {rename foo {}}

test namespace-19.1 {GetNamespaceFromObj, global name found} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1::test_ns_2 {}
    namespace children ::test_ns_1
} {::test_ns_1::test_ns_2}
test namespace-19.2 {GetNamespaceFromObj, relative name found} {
    namespace eval test_ns_1 {
        namespace children test_ns_2
    }
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
    namespace delete test_ns_1::test_ns_2
    namespace eval test_ns_1::test_ns_2::test_ns_3 {}
    lappend l [test_ns_1::foo]
    set l
} {{} ::test_ns_1::test_ns_2::test_ns_3}

test namespace-20.1 {Tcl_NamespaceObjCmd, bad subcommand} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [catch {namespace} msg] $msg
} {1 {wrong # args: should be "namespace subcommand ?arg ...?"}}
test namespace-20.2 {Tcl_NamespaceObjCmd, bad subcommand} {
    list [catch {namespace wombat {}} msg] $msg
} {1 {bad option "wombat": must be children, code, current, delete, ensemble, eval, exists, export, forget, import, inscope, origin, parent, qualifiers, tail, or which}}
test namespace-20.3 {Tcl_NamespaceObjCmd, abbreviations are okay} {
    namespace ch :: test_ns_*
} {}

test namespace-21.1 {NamespaceChildrenCmd, no args} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1::test_ns_2 {}
    expr {[string first ::test_ns_1 [namespace children]] != -1}
} {1}
test namespace-21.2 {NamespaceChildrenCmd, no args} {
    namespace eval test_ns_1 {
        namespace children
    }







|










|







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
    namespace delete test_ns_1::test_ns_2
    namespace eval test_ns_1::test_ns_2::test_ns_3 {}
    lappend l [test_ns_1::foo]
    set l
} {{} ::test_ns_1::test_ns_2::test_ns_3}

test namespace-20.1 {Tcl_NamespaceObjCmd, bad subcommand} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [catch {namespace} msg] $msg
} {1 {wrong # args: should be "namespace subcommand ?arg ...?"}}
test namespace-20.2 {Tcl_NamespaceObjCmd, bad subcommand} {
    list [catch {namespace wombat {}} msg] $msg
} {1 {bad option "wombat": must be children, code, current, delete, ensemble, eval, exists, export, forget, import, inscope, origin, parent, qualifiers, tail, or which}}
test namespace-20.3 {Tcl_NamespaceObjCmd, abbreviations are okay} {
    namespace ch :: test_ns_*
} {}

test namespace-21.1 {NamespaceChildrenCmd, no args} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1::test_ns_2 {}
    expr {[string first ::test_ns_1 [namespace children]] != -1}
} {1}
test namespace-21.2 {NamespaceChildrenCmd, no args} {
    namespace eval test_ns_1 {
        namespace children
    }
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
} {::test_ns_1::test_ns_foo}
test namespace-21.7 {NamespaceChildrenCmd, glob-style pattern given} {
    namespace eval test_ns_1::test_ns_foo {}
    lsort [namespace children test_ns_1 test*]
} [lsort {::test_ns_1::test_ns_2 ::test_ns_1::test_ns_foo}]

test namespace-22.1 {NamespaceCodeCmd, bad args} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [catch {namespace code} msg] $msg \
         [catch {namespace code xxx yyy} msg] $msg
} {1 {wrong # args: should be "namespace code arg"} 1 {wrong # args: should be "namespace code arg"}}
test namespace-22.2 {NamespaceCodeCmd, arg is already scoped value} {
    namespace eval test_ns_1 {
        proc cmd {} {return "test_ns_1::cmd"}
    }







|







675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
} {::test_ns_1::test_ns_foo}
test namespace-21.7 {NamespaceChildrenCmd, glob-style pattern given} {
    namespace eval test_ns_1::test_ns_foo {}
    lsort [namespace children test_ns_1 test*]
} [lsort {::test_ns_1::test_ns_2 ::test_ns_1::test_ns_foo}]

test namespace-22.1 {NamespaceCodeCmd, bad args} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [catch {namespace code} msg] $msg \
         [catch {namespace code xxx yyy} msg] $msg
} {1 {wrong # args: should be "namespace code arg"} 1 {wrong # args: should be "namespace code arg"}}
test namespace-22.2 {NamespaceCodeCmd, arg is already scoped value} {
    namespace eval test_ns_1 {
        proc cmd {} {return "test_ns_1::cmd"}
    }
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
    } 
    namespace eval test_ns_2 [namespace eval test_ns_1 { 
	namespace code {set v} 
    }] 
} {42} 

test namespace-23.1 {NamespaceCurrentCmd, bad args} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [catch {namespace current xxx} msg] $msg \
         [catch {namespace current xxx yyy} msg] $msg
} {1 {wrong # args: should be "namespace current"} 1 {wrong # args: should be "namespace current"}}
test namespace-23.2 {NamespaceCurrentCmd, at global level} {
    namespace current
} {::}
test namespace-23.3 {NamespaceCurrentCmd, in nested ns} {
    namespace eval test_ns_1::test_ns_2 {
        namespace current
    }
} {::test_ns_1::test_ns_2}

test namespace-24.1 {NamespaceDeleteCmd, no args} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace delete
} {}
test namespace-24.2 {NamespaceDeleteCmd, one arg} {
    namespace eval test_ns_1::test_ns_2 {}
    namespace delete ::test_ns_1
} {}
test namespace-24.3 {NamespaceDeleteCmd, two args} {
    namespace eval test_ns_1::test_ns_2 {}
    list [namespace delete ::test_ns_1::test_ns_2] [namespace delete ::test_ns_1]
} {{} {}}
test namespace-24.4 {NamespaceDeleteCmd, unknown ns} {
    list [catch {namespace delete ::test_ns_foo} msg] $msg
} {1 {unknown namespace "::test_ns_foo" in namespace delete command}}

test namespace-25.1 {NamespaceEvalCmd, bad args} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [catch {namespace eval} msg] $msg
} {1 {wrong # args: should be "namespace eval name arg ?arg...?"}}
test namespace-25.2 {NamespaceEvalCmd, bad args} {
    list [catch {namespace test_ns_1} msg] $msg
} {1 {bad option "test_ns_1": must be children, code, current, delete, ensemble, eval, exists, export, forget, import, inscope, origin, parent, qualifiers, tail, or which}}
catch {unset v}
test namespace-25.3 {NamespaceEvalCmd, new namespace} {







|













|















|







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
    } 
    namespace eval test_ns_2 [namespace eval test_ns_1 { 
	namespace code {set v} 
    }] 
} {42} 

test namespace-23.1 {NamespaceCurrentCmd, bad args} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [catch {namespace current xxx} msg] $msg \
         [catch {namespace current xxx yyy} msg] $msg
} {1 {wrong # args: should be "namespace current"} 1 {wrong # args: should be "namespace current"}}
test namespace-23.2 {NamespaceCurrentCmd, at global level} {
    namespace current
} {::}
test namespace-23.3 {NamespaceCurrentCmd, in nested ns} {
    namespace eval test_ns_1::test_ns_2 {
        namespace current
    }
} {::test_ns_1::test_ns_2}

test namespace-24.1 {NamespaceDeleteCmd, no args} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace delete
} {}
test namespace-24.2 {NamespaceDeleteCmd, one arg} {
    namespace eval test_ns_1::test_ns_2 {}
    namespace delete ::test_ns_1
} {}
test namespace-24.3 {NamespaceDeleteCmd, two args} {
    namespace eval test_ns_1::test_ns_2 {}
    list [namespace delete ::test_ns_1::test_ns_2] [namespace delete ::test_ns_1]
} {{} {}}
test namespace-24.4 {NamespaceDeleteCmd, unknown ns} {
    list [catch {namespace delete ::test_ns_foo} msg] $msg
} {1 {unknown namespace "::test_ns_foo" in namespace delete command}}

test namespace-25.1 {NamespaceEvalCmd, bad args} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [catch {namespace eval} msg] $msg
} {1 {wrong # args: should be "namespace eval name arg ?arg...?"}}
test namespace-25.2 {NamespaceEvalCmd, bad args} {
    list [catch {namespace test_ns_1} msg] $msg
} {1 {bad option "test_ns_1": must be children, code, current, delete, ensemble, eval, exists, export, forget, import, inscope, origin, parent, qualifiers, tail, or which}}
catch {unset v}
test namespace-25.3 {NamespaceEvalCmd, new namespace} {
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
"xxxx"
    (in namespace eval "::test_ns_1" script line 1)
    invoked from within
"namespace eval test_ns_1 {xxxx}"}}
catch {unset v}

test namespace-26.1 {NamespaceExportCmd, no args and new ns} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace export
} {}
test namespace-26.2 {NamespaceExportCmd, just -clear arg} {
    namespace export -clear
} {}
test namespace-26.3 {NamespaceExportCmd, pattern can't specify a namespace} {
    namespace eval test_ns_1 {







|







777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
"xxxx"
    (in namespace eval "::test_ns_1" script line 1)
    invoked from within
"namespace eval test_ns_1 {xxxx}"}}
catch {unset v}

test namespace-26.1 {NamespaceExportCmd, no args and new ns} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace export
} {}
test namespace-26.2 {NamespaceExportCmd, just -clear arg} {
    namespace export -clear
} {}
test namespace-26.3 {NamespaceExportCmd, pattern can't specify a namespace} {
    namespace eval test_ns_1 {
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
    namespace eval test_ns_2 {
        namespace import ::test_ns_1::*
    }
    list [lsort [info commands test_ns_2::*]] [test_ns_2::cmd4 hello]
} [list [lsort {::test_ns_2::cmd4 ::test_ns_2::cmd1 ::test_ns_2::cmd3}] {cmd4: hello}]

test namespace-27.1 {NamespaceForgetCmd, no args} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace forget
} {}
test namespace-27.2 {NamespaceForgetCmd, args must be valid namespaces} {
    list [catch {namespace forget ::test_ns_1::xxx} msg] $msg
} {1 {unknown namespace in namespace forget pattern "::test_ns_1::xxx"}}
test namespace-27.3 {NamespaceForgetCmd, arg is forgotten} {
    namespace eval test_ns_1 {
        namespace export cmd*
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_2 {
        namespace import ::test_ns_1::*
        namespace forget ::test_ns_1::cmd1
    }
    info commands ::test_ns_2::*
} {::test_ns_2::cmd2}

test namespace-28.1 {NamespaceImportCmd, no args} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace import
} {}
test namespace-28.2 {NamespaceImportCmd, no args and just "-force"} {
    namespace import -force
} {}
test namespace-28.3 {NamespaceImportCmd, arg is imported} {
    namespace eval test_ns_1 {
        namespace export cmd2
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_2 {
        namespace import ::test_ns_1::*
        namespace forget ::test_ns_1::cmd1
    }
    info commands test_ns_2::*
} {::test_ns_2::cmd2}

test namespace-29.1 {NamespaceInscopeCmd, bad args} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [catch {namespace inscope} msg] $msg
} {1 {wrong # args: should be "namespace inscope name arg ?arg...?"}}
test namespace-29.2 {NamespaceInscopeCmd, bad args} {
    list [catch {namespace inscope ::} msg] $msg
} {1 {wrong # args: should be "namespace inscope name arg ?arg...?"}}
test namespace-29.3 {NamespaceInscopeCmd, specified ns must exist} {
    list [catch {namespace inscope test_ns_1 {set v}} msg] $msg







|



















|



















|







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
    namespace eval test_ns_2 {
        namespace import ::test_ns_1::*
    }
    list [lsort [info commands test_ns_2::*]] [test_ns_2::cmd4 hello]
} [list [lsort {::test_ns_2::cmd4 ::test_ns_2::cmd1 ::test_ns_2::cmd3}] {cmd4: hello}]

test namespace-27.1 {NamespaceForgetCmd, no args} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace forget
} {}
test namespace-27.2 {NamespaceForgetCmd, args must be valid namespaces} {
    list [catch {namespace forget ::test_ns_1::xxx} msg] $msg
} {1 {unknown namespace in namespace forget pattern "::test_ns_1::xxx"}}
test namespace-27.3 {NamespaceForgetCmd, arg is forgotten} {
    namespace eval test_ns_1 {
        namespace export cmd*
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_2 {
        namespace import ::test_ns_1::*
        namespace forget ::test_ns_1::cmd1
    }
    info commands ::test_ns_2::*
} {::test_ns_2::cmd2}

test namespace-28.1 {NamespaceImportCmd, no args} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace import
} {}
test namespace-28.2 {NamespaceImportCmd, no args and just "-force"} {
    namespace import -force
} {}
test namespace-28.3 {NamespaceImportCmd, arg is imported} {
    namespace eval test_ns_1 {
        namespace export cmd2
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_2 {
        namespace import ::test_ns_1::*
        namespace forget ::test_ns_1::cmd1
    }
    info commands test_ns_2::*
} {::test_ns_2::cmd2}

test namespace-29.1 {NamespaceInscopeCmd, bad args} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [catch {namespace inscope} msg] $msg
} {1 {wrong # args: should be "namespace inscope name arg ?arg...?"}}
test namespace-29.2 {NamespaceInscopeCmd, bad args} {
    list [catch {namespace inscope ::} msg] $msg
} {1 {wrong # args: should be "namespace inscope name arg ?arg...?"}}
test namespace-29.3 {NamespaceInscopeCmd, specified ns must exist} {
    list [catch {namespace inscope test_ns_1 {set v}} msg] $msg
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
} {::test_ns_1::cmd: v=747, args=}
test namespace-29.5 {NamespaceInscopeCmd, has lappend semantics} {
    list [namespace inscope test_ns_1 cmd x y z] \
         [namespace eval test_ns_1 [concat cmd [list x y z]]]
} {{::test_ns_1::cmd: v=747, args=x y z} {::test_ns_1::cmd: v=747, args=x y z}}

test namespace-30.1 {NamespaceOriginCmd, bad args} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [catch {namespace origin} msg] $msg
} {1 {wrong # args: should be "namespace origin name"}}
test namespace-30.2 {NamespaceOriginCmd, bad args} {
    list [catch {namespace origin x y} msg] $msg
} {1 {wrong # args: should be "namespace origin name"}}
test namespace-30.3 {NamespaceOriginCmd, command not found} {
    list [catch {namespace origin fred} msg] $msg







|







891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
} {::test_ns_1::cmd: v=747, args=}
test namespace-29.5 {NamespaceInscopeCmd, has lappend semantics} {
    list [namespace inscope test_ns_1 cmd x y z] \
         [namespace eval test_ns_1 [concat cmd [list x y z]]]
} {{::test_ns_1::cmd: v=747, args=x y z} {::test_ns_1::cmd: v=747, args=x y z}}

test namespace-30.1 {NamespaceOriginCmd, bad args} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [catch {namespace origin} msg] $msg
} {1 {wrong # args: should be "namespace origin name"}}
test namespace-30.2 {NamespaceOriginCmd, bad args} {
    list [catch {namespace origin x y} msg] $msg
} {1 {wrong # args: should be "namespace origin name"}}
test namespace-30.3 {NamespaceOriginCmd, command not found} {
    list [catch {namespace origin fred} msg] $msg
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
             [namespace origin p] \
             [namespace origin cmd1] \
             [namespace origin ::test_ns_2::cmd2]
    }
} {::foreach ::test_ns_2::p ::test_ns_1::cmd1 ::test_ns_1::cmd2}

test namespace-31.1 {NamespaceParentCmd, bad args} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [catch {namespace parent a b} msg] $msg
} {1 {wrong # args: should be "namespace parent ?name?"}}
test namespace-31.2 {NamespaceParentCmd, no args} {
    namespace parent
} {}
test namespace-31.3 {NamespaceParentCmd, namespace specified} {
    namespace eval test_ns_1 {
        namespace eval test_ns_2 {
            namespace eval test_ns_3 {}
        }
    }
    list [namespace parent ::] \
         [namespace parent test_ns_1::test_ns_2] \
         [namespace eval test_ns_1::test_ns_2::test_ns_3 {namespace parent ::test_ns_1::test_ns_2}]
} {{} ::test_ns_1 ::test_ns_1}
test namespace-31.4 {NamespaceParentCmd, bad namespace specified} {
    list [catch {namespace parent test_ns_1::test_ns_foo} msg] $msg
} {1 {unknown namespace "test_ns_1::test_ns_foo" in namespace parent command}}

test namespace-32.1 {NamespaceQualifiersCmd, bad args} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [catch {namespace qualifiers} msg] $msg
} {1 {wrong # args: should be "namespace qualifiers string"}}
test namespace-32.2 {NamespaceQualifiersCmd, bad args} {
    list [catch {namespace qualifiers x y} msg] $msg
} {1 {wrong # args: should be "namespace qualifiers string"}}
test namespace-32.3 {NamespaceQualifiersCmd, simple name} {
    namespace qualifiers foo







|




















|







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
             [namespace origin p] \
             [namespace origin cmd1] \
             [namespace origin ::test_ns_2::cmd2]
    }
} {::foreach ::test_ns_2::p ::test_ns_1::cmd1 ::test_ns_1::cmd2}

test namespace-31.1 {NamespaceParentCmd, bad args} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [catch {namespace parent a b} msg] $msg
} {1 {wrong # args: should be "namespace parent ?name?"}}
test namespace-31.2 {NamespaceParentCmd, no args} {
    namespace parent
} {}
test namespace-31.3 {NamespaceParentCmd, namespace specified} {
    namespace eval test_ns_1 {
        namespace eval test_ns_2 {
            namespace eval test_ns_3 {}
        }
    }
    list [namespace parent ::] \
         [namespace parent test_ns_1::test_ns_2] \
         [namespace eval test_ns_1::test_ns_2::test_ns_3 {namespace parent ::test_ns_1::test_ns_2}]
} {{} ::test_ns_1 ::test_ns_1}
test namespace-31.4 {NamespaceParentCmd, bad namespace specified} {
    list [catch {namespace parent test_ns_1::test_ns_foo} msg] $msg
} {1 {unknown namespace "test_ns_1::test_ns_foo" in namespace parent command}}

test namespace-32.1 {NamespaceQualifiersCmd, bad args} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [catch {namespace qualifiers} msg] $msg
} {1 {wrong # args: should be "namespace qualifiers string"}}
test namespace-32.2 {NamespaceQualifiersCmd, bad args} {
    list [catch {namespace qualifiers x y} msg] $msg
} {1 {wrong # args: should be "namespace qualifiers string"}}
test namespace-32.3 {NamespaceQualifiersCmd, simple name} {
    namespace qualifiers foo
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
    namespace qualifiers :::::
} {}
test namespace-32.8 {NamespaceQualifiersCmd, odd number of :s} {
    namespace qualifiers foo:::
} {foo}

test namespace-33.1 {NamespaceTailCmd, bad args} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [catch {namespace tail} msg] $msg
} {1 {wrong # args: should be "namespace tail string"}}
test namespace-33.2 {NamespaceTailCmd, bad args} {
    list [catch {namespace tail x y} msg] $msg
} {1 {wrong # args: should be "namespace tail string"}}
test namespace-33.3 {NamespaceTailCmd, simple name} {
    namespace tail foo







|







971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
    namespace qualifiers :::::
} {}
test namespace-32.8 {NamespaceQualifiersCmd, odd number of :s} {
    namespace qualifiers foo:::
} {foo}

test namespace-33.1 {NamespaceTailCmd, bad args} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [catch {namespace tail} msg] $msg
} {1 {wrong # args: should be "namespace tail string"}}
test namespace-33.2 {NamespaceTailCmd, bad args} {
    list [catch {namespace tail x y} msg] $msg
} {1 {wrong # args: should be "namespace tail string"}}
test namespace-33.3 {NamespaceTailCmd, simple name} {
    namespace tail foo
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
    namespace tail :::::
} {}
test namespace-33.8 {NamespaceTailCmd, odd number of :s} {
    namespace tail foo:::
} {}

test namespace-34.1 {NamespaceWhichCmd, bad args} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [catch {namespace which} msg] $msg
} {1 {wrong # args: should be "namespace which ?-command? ?-variable? name"}}
test namespace-34.2 {NamespaceWhichCmd, bad args} {
    list [catch {namespace which -fred} msg] $msg
} {1 {wrong # args: should be "namespace which ?-command? ?-variable? name"}}
test namespace-34.3 {NamespaceWhichCmd, bad args} {
    list [catch {namespace which -command} msg] $msg







|







997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
    namespace tail :::::
} {}
test namespace-33.8 {NamespaceTailCmd, odd number of :s} {
    namespace tail foo:::
} {}

test namespace-34.1 {NamespaceWhichCmd, bad args} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [catch {namespace which} msg] $msg
} {1 {wrong # args: should be "namespace which ?-command? ?-variable? name"}}
test namespace-34.2 {NamespaceWhichCmd, bad args} {
    list [catch {namespace which -fred} msg] $msg
} {1 {wrong # args: should be "namespace which ?-command? ?-variable? name"}}
test namespace-34.3 {NamespaceWhichCmd, bad args} {
    list [catch {namespace which -command} msg] $msg
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
             [namespace which -variable v3] \
             [namespace which -variable ::test_ns_2::v2] \
             [catch {namespace which -variable ::test_ns_2::noSuchVar} msg] $msg
    }
} {::env ::test_ns_3::v3 ::test_ns_2::v2 0 {}}

test namespace-35.1 {FreeNsNameInternalRep, resulting ref count > 0} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        proc p {} {
            namespace delete [namespace current]
            return [namespace current]
        }
    }
    test_ns_1::p







|







1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
             [namespace which -variable v3] \
             [namespace which -variable ::test_ns_2::v2] \
             [catch {namespace which -variable ::test_ns_2::noSuchVar} msg] $msg
    }
} {::env ::test_ns_3::v3 ::test_ns_2::v2 0 {}}

test namespace-35.1 {FreeNsNameInternalRep, resulting ref count > 0} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        proc p {} {
            namespace delete [namespace current]
            return [namespace current]
        }
    }
    test_ns_1::p
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
         [namespace delete test_ns_1] \
         [catch {test_ns_1::q} msg] $msg
} {::test_ns_1 {} 1 {invalid command name "test_ns_1::q"}}

catch {unset x}
catch {unset y}
test namespace-36.1 {DupNsNameInternalRep} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1 {}
    set x "::test_ns_1"
    list [namespace parent $x] [set y $x] [namespace parent $y]
} {:: ::test_ns_1 ::}
catch {unset x}
catch {unset y}

test namespace-37.1 {SetNsNameFromAny, ns name found} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1::test_ns_2 {}
    namespace eval test_ns_1 {
        namespace children ::test_ns_1
    }
} {::test_ns_1::test_ns_2}
test namespace-37.2 {SetNsNameFromAny, ns name not found} {
    namespace eval test_ns_1 {
        list [catch {namespace children ::test_ns_1::test_ns_foo} msg] $msg
    }
} {1 {unknown namespace "::test_ns_1::test_ns_foo" in namespace children command}}

test namespace-38.1 {UpdateStringOfNsName} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    ;# Tcl_NamespaceObjCmd calls UpdateStringOfNsName to get subcmd name
    list [namespace eval {} {namespace current}] \
         [namespace eval {} {namespace current}]
} {:: ::}

test namespace-39.1 {NamespaceExistsCmd} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval ::test_ns_z::test_me { variable foo }
    list [namespace exists ::] \
	    [namespace exists ::bogus_namespace] \
	    [namespace exists ::test_ns_z] \
	    [namespace exists test_ns_z] \
	    [namespace exists ::test_ns_z::foo] \
	    [namespace exists ::test_ns_z::test_me] \







|








|












|






|







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
         [namespace delete test_ns_1] \
         [catch {test_ns_1::q} msg] $msg
} {::test_ns_1 {} 1 {invalid command name "test_ns_1::q"}}

catch {unset x}
catch {unset y}
test namespace-36.1 {DupNsNameInternalRep} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1 {}
    set x "::test_ns_1"
    list [namespace parent $x] [set y $x] [namespace parent $y]
} {:: ::test_ns_1 ::}
catch {unset x}
catch {unset y}

test namespace-37.1 {SetNsNameFromAny, ns name found} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1::test_ns_2 {}
    namespace eval test_ns_1 {
        namespace children ::test_ns_1
    }
} {::test_ns_1::test_ns_2}
test namespace-37.2 {SetNsNameFromAny, ns name not found} {
    namespace eval test_ns_1 {
        list [catch {namespace children ::test_ns_1::test_ns_foo} msg] $msg
    }
} {1 {unknown namespace "::test_ns_1::test_ns_foo" in namespace children command}}

test namespace-38.1 {UpdateStringOfNsName} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    ;# Tcl_NamespaceObjCmd calls UpdateStringOfNsName to get subcmd name
    list [namespace eval {} {namespace current}] \
         [namespace eval {} {namespace current}]
} {:: ::}

test namespace-39.1 {NamespaceExistsCmd} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval ::test_ns_z::test_me { variable foo }
    list [namespace exists ::] \
	    [namespace exists ::bogus_namespace] \
	    [namespace exists ::test_ns_z] \
	    [namespace exists test_ns_z] \
	    [namespace exists ::test_ns_z::foo] \
	    [namespace exists ::test_ns_z::test_me] \
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
	proc a args {format 1,[llength $args]}
	proc b args {format 2,[llength $args]}
	proc c args {format 3,[llength $args]}
	proc d args {format 4,[llength $args]}
	namespace ensemble create -subcommands {b c}
    }
}
test namespace-43.3 {ensembles: list-driven} {
    eval $SETUP
    namespace delete ns
} {}
test namespace-43.4 {ensembles: list-driven} -setup $SETUP -body {
    ns a foo bar boo spong wibble
} -cleanup {namespace delete ns} -returnCodes error -result {unknown or ambiguous subcommand "a": must be b, or c}
test namespace-43.5 {ensembles: list-driven} -setup $SETUP -body {
    ns b foo bar boo spong wibble
} -cleanup {namespace delete ns} -result 2,5
test namespace-43.6 {ensembles: list-driven} -setup $SETUP -body {







|
<

|







1305
1306
1307
1308
1309
1310
1311
1312

1313
1314
1315
1316
1317
1318
1319
1320
1321
	proc a args {format 1,[llength $args]}
	proc b args {format 2,[llength $args]}
	proc c args {format 3,[llength $args]}
	proc d args {format 4,[llength $args]}
	namespace ensemble create -subcommands {b c}
    }
}
test namespace-43.3 {ensembles: list-driven} -setup $SETUP -body {

    namespace delete ns
} -result {}
test namespace-43.4 {ensembles: list-driven} -setup $SETUP -body {
    ns a foo bar boo spong wibble
} -cleanup {namespace delete ns} -returnCodes error -result {unknown or ambiguous subcommand "a": must be b, or c}
test namespace-43.5 {ensembles: list-driven} -setup $SETUP -body {
    ns b foo bar boo spong wibble
} -cleanup {namespace delete ns} -result 2,5
test namespace-43.6 {ensembles: list-driven} -setup $SETUP -body {
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
	proc a args {format 1,[llength $args]}
	proc b args {format 2,[llength $args]}
	proc c args {format 3,[llength $args]}
	proc d args {format 4,[llength $args]}
	namespace ensemble create -subcommands {b c} -map {c ::ns::d}
    }
}
test namespace-43.8 {ensembles: list-and-map-driven} {
    eval $SETUP
    namespace delete ns
} {}
test namespace-43.9 {ensembles: list-and-map-driven} -setup $SETUP -body {
    ns a foo bar boo spong wibble
} -cleanup {namespace delete ns} -returnCodes error -result {unknown or ambiguous subcommand "a": must be b, or c}
test namespace-43.10 {ensembles: list-and-map-driven} -setup $SETUP -body {
    ns b foo bar boo spong wibble
} -cleanup {namespace delete ns} -result 2,5
test namespace-43.11 {ensembles: list-and-map-driven} -setup $SETUP -body {
    ns c foo bar boo spong wibble
} -cleanup {namespace delete ns} -result 4,5
test namespace-43.12 {ensembles: list-and-map-driven} -setup $SETUP -body {
    ns d foo bar boo spong wibble
} -cleanup {namespace delete ns} -returnCodes error -result {unknown or ambiguous subcommand "d": must be b, or c}
set SETUP {
    namespace eval ns {
	namespace export *
	proc foo args {format bar}
	proc spong args {format wibble}
	namespace ensemble create -prefixes off
    }
}
test namespace-43.13 {ensembles: turn off prefixes} {
    eval $SETUP
    namespace delete ns
} {}
test namespace-43.14 {ensembles: turn off prefixes} -setup $SETUP -body {
    ns fo
} -cleanup {namespace delete ns} -returnCodes error -result {unknown subcommand "fo": must be foo, or spong}
test namespace-43.15 {ensembles: turn off prefixes} -setup $SETUP -body {
    ns foo
} -cleanup {namespace delete ns} -result bar
test namespace-43.16 {ensembles: turn off prefixes} -setup $SETUP -body {







|
<

|




















|
<

|







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
	proc a args {format 1,[llength $args]}
	proc b args {format 2,[llength $args]}
	proc c args {format 3,[llength $args]}
	proc d args {format 4,[llength $args]}
	namespace ensemble create -subcommands {b c} -map {c ::ns::d}
    }
}
test namespace-43.8 {ensembles: list-and-map-driven} -setup $SETUP -body {

    namespace delete ns
} -result {}
test namespace-43.9 {ensembles: list-and-map-driven} -setup $SETUP -body {
    ns a foo bar boo spong wibble
} -cleanup {namespace delete ns} -returnCodes error -result {unknown or ambiguous subcommand "a": must be b, or c}
test namespace-43.10 {ensembles: list-and-map-driven} -setup $SETUP -body {
    ns b foo bar boo spong wibble
} -cleanup {namespace delete ns} -result 2,5
test namespace-43.11 {ensembles: list-and-map-driven} -setup $SETUP -body {
    ns c foo bar boo spong wibble
} -cleanup {namespace delete ns} -result 4,5
test namespace-43.12 {ensembles: list-and-map-driven} -setup $SETUP -body {
    ns d foo bar boo spong wibble
} -cleanup {namespace delete ns} -returnCodes error -result {unknown or ambiguous subcommand "d": must be b, or c}
set SETUP {
    namespace eval ns {
	namespace export *
	proc foo args {format bar}
	proc spong args {format wibble}
	namespace ensemble create -prefixes off
    }
}
test namespace-43.13 {ensembles: turn off prefixes} -setup $SETUP -body {

    namespace delete ns
} -result {}
test namespace-43.14 {ensembles: turn off prefixes} -setup $SETUP -body {
    ns fo
} -cleanup {namespace delete ns} -returnCodes error -result {unknown subcommand "fo": must be foo, or spong}
test namespace-43.15 {ensembles: turn off prefixes} -setup $SETUP -body {
    ns foo
} -cleanup {namespace delete ns} -result bar
test namespace-43.16 {ensembles: turn off prefixes} -setup $SETUP -body {
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
"foo bar"}}

# cleanup
catch {rename cmd1 {}}
catch {unset l}
catch {unset msg}
catch {unset trigger}
eval namespace delete [namespace children :: test_ns_*]
::tcltest::cleanupTests
return







|


1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
"foo bar"}}

# cleanup
catch {rename cmd1 {}}
catch {unset l}
catch {unset msg}
catch {unset trigger}
namespace delete {expand}[namespace children :: test_ns_*]
::tcltest::cleanupTests
return
Changes to tests/parse.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
# This file contains a collection of tests for the procedures in the
# file tclParse.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.
#
# RCS: @(#) $Id: parse.test,v 1.15.2.1 2003/08/07 21:36:04 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest

    namespace import -force ::tcltest::*
}

if {[info commands testparser] == {}} {
    puts "This application hasn't been compiled with the \"testparser\""
    puts "command, so I can't test the Tcl parser."
    ::tcltest::cleanupTests
    return 
}








test parse-1.1 {Tcl_ParseCommand procedure, computing string length} {
    testparser [bytestring "foo\0 bar"] -1
} {- foo 1 simple foo 1 text foo 0 {}}
test parse-1.2 {Tcl_ParseCommand procedure, computing string length} {
    testparser "foo bar" -1
} {- {foo bar} 2 simple foo 1 text foo 0 simple bar 1 text bar 0 {}}
test parse-1.3 {Tcl_ParseCommand procedure, leading space} {
    testparser "  \n\t   foo" 0
} {- foo 1 simple foo 1 text foo 0 {}}
test parse-1.4 {Tcl_ParseCommand procedure, leading space} {
    testparser "\f\r\vfoo" 0
} {- foo 1 simple foo 1 text foo 0 {}}
test parse-1.5 {Tcl_ParseCommand procedure, backslash-newline in leading space} {
    testparser "  \\\n foo" 0
} {- foo 1 simple foo 1 text foo 0 {}}
test parse-1.6 {Tcl_ParseCommand procedure, backslash-newline in leading space} {
    testparser {  \a foo} 0
} {- {\a foo} 2 word {\a} 1 backslash {\a} 0 simple foo 1 text foo 0 {}}
test parse-1.7 {Tcl_ParseCommand procedure, missing continuation line in leading space} {
    testparser "   \\\n" 0
} {- {} 0 {}}
test parse-1.8 {Tcl_ParseCommand procedure, eof in leading space} {
    testparser "      foo" 3
} {- {} 0 {   foo}}

test parse-2.1 {Tcl_ParseCommand procedure, comments} {
    testparser "# foo bar\n foo" 0
} {{# foo bar
} foo 1 simple foo 1 text foo 0 {}}
test parse-2.2 {Tcl_ParseCommand procedure, several comments} {
    testparser " # foo bar\n # another comment\n\n   foo" 0
} {{# foo bar
 # another comment
} foo 1 simple foo 1 text foo 0 {}}
test parse-2.3 {Tcl_ParseCommand procedure, backslash-newline in comments} {
    testparser " # foo bar\\\ncomment on continuation line\nfoo" 0
} {\#\ foo\ bar\\\ncomment\ on\ continuation\ line\n foo 1 simple foo 1 text foo 0 {}}
test parse-2.4 {Tcl_ParseCommand procedure, missing continuation line in comment} {
    testparser "#   \\\n" 0
} {\#\ \ \ \\\n {} 0 {}}
test parse-2.5 {Tcl_ParseCommand procedure, eof in comment} {
    testparser " # foo bar\nfoo" 8
} {{# foo b} {} 0 {ar
foo}}

test parse-3.1 {Tcl_ParseCommand procedure, parsing words, skipping space} {
    testparser "foo  bar\t\tx" 0
} {- {foo  bar		x} 3 simple foo 1 text foo 0 simple bar 1 text bar 0 simple x 1 text x 0 {}}
test parse-3.2 {Tcl_ParseCommand procedure, missing continuation line in leading space} {
    testparser "abc  \\\n" 0
} {- abc\ \ \\\n 1 simple abc 1 text abc 0 {}}
test parse-3.3 {Tcl_ParseCommand procedure, parsing words, command ends in space} {
    testparser "foo  ;  bar x" 0
} {- {foo  ;} 1 simple foo 1 text foo 0 {  bar x}}
test parse-3.4 {Tcl_ParseCommand procedure, parsing words, command ends in space} {
    testparser "foo       " 5
} {- {foo  } 1 simple foo 1 text foo 0 {     }}
test parse-3.5 {Tcl_ParseCommand procedure, quoted words} {
    testparser {foo "a b c" d "efg";} 0
} {- {foo "a b c" d "efg";} 4 simple foo 1 text foo 0 simple {"a b c"} 1 text {a b c} 0 simple d 1 text d 0 simple {"efg"} 1 text efg 0 {}}
test parse-3.6 {Tcl_ParseCommand procedure, words in braces} {
    testparser {foo {a $b [concat foo]} {c d}} 0
} {- {foo {a $b [concat foo]} {c d}} 3 simple foo 1 text foo 0 simple {{a $b [concat foo]}} 1 text {a $b [concat foo]} 0 simple {{c d}} 1 text {c d} 0 {}}
test parse-3.7 {Tcl_ParseCommand procedure, error in unquoted word} {
    list [catch {testparser "foo \$\{abc" 0} msg] $msg $errorInfo
} {1 {missing close-brace for variable name} missing\ close-brace\ for\ variable\ name\n\ \ \ \ (remainder\ of\ script:\ \"\{abc\")\n\ \ \ \ invoked\ from\ within\n\"testparser\ \"foo\ \\\$\\\{abc\"\ 0\"}

test parse-4.1 {Tcl_ParseCommand procedure, simple words} {
    testparser {foo} 0
} {- foo 1 simple foo 1 text foo 0 {}}
test parse-4.2 {Tcl_ParseCommand procedure, simple words} {
    testparser {{abc}} 0
} {- {{abc}} 1 simple {{abc}} 1 text abc 0 {}}
test parse-4.3 {Tcl_ParseCommand procedure, simple words} {
    testparser {"c d"} 0
} {- {"c d"} 1 simple {"c d"} 1 text {c d} 0 {}}
test parse-4.4 {Tcl_ParseCommand procedure, simple words} {
    testparser {x$d} 0
} {- {x$d} 1 word {x$d} 3 text x 0 variable {$d} 1 text d 0 {}}
test parse-4.5 {Tcl_ParseCommand procedure, simple words} {
    testparser {"a [foo] b"} 0
} {- {"a [foo] b"} 1 word {"a [foo] b"} 3 text {a } 0 command {[foo]} 0 text { b} 0 {}}
test parse-4.6 {Tcl_ParseCommand procedure, simple words} {
    testparser {$x} 0
} {- {$x} 1 word {$x} 2 variable {$x} 1 text x 0 {}}

test parse-5.1 {Tcl_ParseCommand procedure, backslash-newline terminates word} {
    testparser "{abc}\\\n" 0
} {- \{abc\}\\\n 1 simple {{abc}} 1 text abc 0 {}}
test parse-5.2 {Tcl_ParseCommand procedure, backslash-newline terminates word} {
    testparser "foo\\\nbar" 0
} {- foo\\\nbar 2 simple foo 1 text foo 0 simple bar 1 text bar 0 {}}
test parse-5.3 {Tcl_ParseCommand procedure, word terminator is command terminator} {
    testparser "foo\n bar" 0
} {- {foo
} 1 simple foo 1 text foo 0 { bar}}
test parse-5.4 {Tcl_ParseCommand procedure, word terminator is command terminator} {
    testparser "foo; bar" 0
} {- {foo;} 1 simple foo 1 text foo 0 { bar}}
test parse-5.5 {Tcl_ParseCommand procedure, word terminator is end of string} {
    testparser "\"foo\" bar" 5
} {- {"foo"} 1 simple {"foo"} 1 text foo 0 { bar}}
test parse-5.6 {Tcl_ParseCommand procedure, junk after close quote} {
    list [catch {testparser {foo "bar"x} 0} msg] $msg $errorInfo
} {1 {extra characters after close-quote} {extra characters after close-quote
    (remainder of script: "x")
    invoked from within
"testparser {foo "bar"x} 0"}}
test parse-5.7 {Tcl_ParseCommand procedure, backslash-newline after close quote} {
    testparser "foo \"bar\"\\\nx" 0
} {- foo\ \"bar\"\\\nx 3 simple foo 1 text foo 0 simple {"bar"} 1 text bar 0 simple x 1 text x 0 {}}
test parse-5.8 {Tcl_ParseCommand procedure, junk after close brace} {
    list [catch {testparser {foo {bar}x} 0} msg] $msg $errorInfo
} {1 {extra characters after close-brace} {extra characters after close-brace
    (remainder of script: "x")
    invoked from within
"testparser {foo {bar}x} 0"}}
test parse-5.9 {Tcl_ParseCommand procedure, backslash-newline after close brace} {
    testparser "foo {bar}\\\nx" 0
} {- foo\ \{bar\}\\\nx 3 simple foo 1 text foo 0 simple {{bar}} 1 text bar 0 simple x 1 text x 0 {}}
test parse-5.10 {Tcl_ParseCommand procedure, multiple deletion of non-static buffer} {
    # This test is designed to catch bug 1681.
    list [catch {testparser "a \"\\1\\2\\3\\4\\5\\6\\7\\8\\9\\1\\2\\3\\4\\5\\6\\7\\8" 0} msg] $msg $errorInfo
} "1 {missing \"} {missing \"
    (remainder of script: \"\"\\1\\2\\3\\4\\5\\6\\7\\8\\9\\1\\2\\3\\4\\5\\6\\7\\8\")
    invoked from within
\"testparser \"a \\\"\\\\1\\\\2\\\\3\\\\4\\\\5\\\\6\\\\7\\\\8\\\\9\\\\1\\\\2\\\\3\\\\4\\\\5\\\\6\\\\7\\\\8\" 0\"}"







































































test parse-6.1 {ParseTokens procedure, empty word} {
    testparser {""} 0
} {- {""} 1 simple {""} 1 text {} 0 {}}
test parse-6.2 {ParseTokens procedure, simple range} {
    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 {}}
test parse-6.3 {ParseTokens procedure, variable reference} {
    testparser {abc$x.e $y(z)} 0
} {- {abc$x.e $y(z)} 2 word {abc$x.e} 4 text abc 0 variable {$x} 1 text x 0 text .e 0 word {$y(z)} 3 variable {$y(z)} 2 text y 0 text z 0 {}}
test parse-6.4 {ParseTokens procedure, variable reference} {
    list [catch {testparser {$x([a )} 0} msg] $msg
} {1 {missing close-bracket}}
test parse-6.5 {ParseTokens procedure, command substitution} {
    testparser {[foo $x bar]z} 0
} {- {[foo $x bar]z} 1 word {[foo $x bar]z} 2 command {[foo $x bar]} 0 text z 0 {}}
test parse-6.6 {ParseTokens procedure, command substitution} {
    testparser {[foo \] [a b]]} 0
} {- {[foo \] [a b]]} 1 word {[foo \] [a b]]} 1 command {[foo \] [a b]]} 0 {}}
test parse-6.7 {ParseTokens procedure, error in command substitution} {
    list [catch {testparser {a [b {}c d] e} 0} msg] $msg $errorInfo
} {1 {extra characters after close-brace} {extra characters after close-brace
    (remainder of script: "c d] e")
    invoked from within
"testparser {a [b {}c d] e} 0"}}
test parse-6.8 {ParseTokens procedure, error in command substitution} {
    info complete {a [b {}c d]}
} {1}
test parse-6.9 {ParseTokens procedure, error in command substitution} {
    info complete {a [b "c d}
} {0}
test parse-6.10 {ParseTokens procedure, incomplete sub-command} {
    info complete {puts [
	expr 1+1
	#this is a comment ]}
} {0}
test parse-6.11 {ParseTokens procedure, memory allocation for big nested command} {
    testparser {[$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b)]} 0
} {- {[$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b)]} 1 word {[$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b)]} 1 command {[$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b)]} 0 {}}
test parse-6.12 {ParseTokens procedure, missing close bracket} {
    list [catch {testparser {[foo $x bar} 0} msg] $msg $errorInfo
} {1 {missing close-bracket} {missing close-bracket
    (remainder of script: "[foo $x bar")
    invoked from within
"testparser {[foo $x bar} 0"}}
test parse-6.13 {ParseTokens procedure, backslash-newline without continuation line} {
    list [catch {testparser "\"a b\\\n" 0} msg] $msg $errorInfo
} {1 {missing "} missing\ \"\n\ \ \ \ (remainder\ of\ script:\ \"\"a\ b\\\n\")\n\ \ \ \ invoked\ from\ within\n\"testparser\ \"\\\"a\ b\\\\\\n\"\ 0\"}
test parse-6.14 {ParseTokens procedure, backslash-newline} {
    testparser "b\\\nc" 0
} {- b\\\nc 2 simple b 1 text b 0 simple c 1 text c 0 {}}
test parse-6.15 {ParseTokens procedure, backslash-newline} {
    testparser "\"b\\\nc\"" 0
} {- \"b\\\nc\" 1 word \"b\\\nc\" 3 text b 0 backslash \\\n 0 text c 0 {}}
test parse-6.16 {ParseTokens procedure, backslash substitution} {
    testparser {\n\a\x7f} 0
} {- {\n\a\x7f} 1 word {\n\a\x7f} 3 backslash {\n} 0 backslash {\a} 0 backslash {\x7f} 0 {}}
test parse-6.17 {ParseTokens procedure, null characters} {
    testparser [bytestring "foo\0zz"] 0
} "- [bytestring foo\0zz] 1 word [bytestring foo\0zz] 3 text foo 0 text [bytestring \0] 0 text zz 0 {}"
test parse-6.18 {ParseTokens procedure, seek past numBytes for close-bracket} {
    # Test for Bug 681841
    list [catch {testparser {[a]} 2} msg] $msg
} {1 {missing close-bracket}}

test parse-7.1 {Tcl_FreeParse and ExpandTokenArray procedures} {
    testparser {$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) } 0
} {- {$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) } 16 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 {}}

test parse-8.1 {Tcl_EvalObjv procedure} {
    testevalobjv 0 concat this is a test
} {this is a test}
test parse-8.2 {Tcl_EvalObjv procedure, unknown commands} {
    rename unknown unknown.old
    set x [catch {testevalobjv 10 asdf poiu} msg]
    rename unknown.old unknown
    list $x $msg
} {1 {invalid command name "asdf"}}
test parse-8.3 {Tcl_EvalObjv procedure, unknown commands} {
    rename unknown unknown.old
    proc unknown args {
	return "unknown $args"
    }
    set x [catch {testevalobjv 0 asdf poiu} msg]
    rename unknown {}
    rename unknown.old unknown
    list $x $msg
} {0 {unknown asdf poiu}}
test parse-8.4 {Tcl_EvalObjv procedure, unknown commands} {
    rename unknown unknown.old
    proc unknown args {
	error "I don't like that command"
    }
    set x [catch {testevalobjv 0 asdf poiu} msg]
    rename unknown {}
    rename unknown.old unknown
    list $x $msg
} {1 {I don't like that command}}
test parse-8.5 {Tcl_EvalObjv procedure, command traces} {
    testevalobjv 0 set x 123
    testcmdtrace tracetest {testevalobjv 0 set x $x}
} {{testevalobjv 0 set x $x} {testevalobjv 0 set x 123} {set x 123} {set x 123}}
test parse-8.7 {Tcl_EvalObjv procedure, TCL_EVAL_GLOBAL flag} {


    proc x {} {
	set y 23
	set z [testevalobjv 1 set y]
	return [list $z $y]
    }
    catch {unset y}

    set y 16

    x
} {16 23}
test parse-8.8 {Tcl_EvalObjv procedure, async handlers} {




    proc async1 {result code} {

	global aresult acode
	set aresult $result
	set acode $code
	return "new result"
    }
    set handler1 [testasync create async1]
    set aresult xxx
    set acode yyy
    set x [list [catch [list testevalobjv 0 testasync mark $handler1 original 0] msg] $msg $acode $aresult]
    testasync delete
    set x

} {0 {new result} 0 original}
test parse-8.9 {Tcl_EvalObjv procedure, exceptional return} {
    list [catch {testevalobjv 0 error message} msg] $msg
} {1 message}

test parse-9.1 {Tcl_LogCommandInfo, line numbers} {
    catch {unset x}
    list [catch {testevalex {for {} 1 {} {


	# asdf
	set x
    }}}] $errorInfo










|

<
|
>
|


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

|


|


|


|


|


|


|


|



|



|




|


|


|




|


|


|


|


|


|


|



|


|


|


|


|


|



|


|


|



|


|


|





|


|





|


|







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


|


|


|


|


|


|
















|


|





|


|


|


|


|


|




|



|


|
|

|


|
|
|



|
|


|
|
|



|
|


|



|
>
>





|
>
|
>

|
|
>
>
>
>

>
|







|

|
>
|
|



|







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
# This file contains a collection of tests for the procedures in the
# file tclParse.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.
#
# RCS: @(#) $Id: parse.test,v 1.15.2.2 2004/02/07 05:48:03 dgp Exp $


if {[catch {package require tcltest 2.0.2}]} {
    puts stderr "Skipping tests in [info script]. tcltest 2.0.2 required."
    return
}

namespace eval ::tcl::test::parse {
    namespace import ::tcltest::test
    namespace import ::tcltest::testConstraint
    namespace import ::tcltest::cleanupTests
    namespace import ::tcltest::bytestring

    testConstraint testparser [llength [info commands testparser]]
    testConstraint testevalobjv [llength [info commands testevalobjv]]
    testConstraint testevalex [llength [info commands testevalex]]
    testConstraint testparsevarname [llength [info commands testparsevarname]]
    testConstraint testparsevar [llength [info commands testparsevar]]
    testConstraint testasync [llength [info commands testasync]]
    testConstraint testcmdtrace [llength [info commands testcmdtrace]]

test parse-1.1 {Tcl_ParseCommand procedure, computing string length} testparser {
    testparser [bytestring "foo\0 bar"] -1
} {- foo 1 simple foo 1 text foo 0 {}}
test parse-1.2 {Tcl_ParseCommand procedure, computing string length} testparser {
    testparser "foo bar" -1
} {- {foo bar} 2 simple foo 1 text foo 0 simple bar 1 text bar 0 {}}
test parse-1.3 {Tcl_ParseCommand procedure, leading space} testparser {
    testparser "  \n\t   foo" 0
} {- foo 1 simple foo 1 text foo 0 {}}
test parse-1.4 {Tcl_ParseCommand procedure, leading space} testparser {
    testparser "\f\r\vfoo" 0
} {- foo 1 simple foo 1 text foo 0 {}}
test parse-1.5 {Tcl_ParseCommand procedure, backslash-newline in leading space} testparser {
    testparser "  \\\n foo" 0
} {- foo 1 simple foo 1 text foo 0 {}}
test parse-1.6 {Tcl_ParseCommand procedure, backslash-newline in leading space} testparser {
    testparser {  \a foo} 0
} {- {\a foo} 2 word {\a} 1 backslash {\a} 0 simple foo 1 text foo 0 {}}
test parse-1.7 {Tcl_ParseCommand procedure, missing continuation line in leading space} testparser {
    testparser "   \\\n" 0
} {- {} 0 {}}
test parse-1.8 {Tcl_ParseCommand procedure, eof in leading space} testparser {
    testparser "      foo" 3
} {- {} 0 {   foo}}

test parse-2.1 {Tcl_ParseCommand procedure, comments} testparser {
    testparser "# foo bar\n foo" 0
} {{# foo bar
} foo 1 simple foo 1 text foo 0 {}}
test parse-2.2 {Tcl_ParseCommand procedure, several comments} testparser {
    testparser " # foo bar\n # another comment\n\n   foo" 0
} {{# foo bar
 # another comment
} foo 1 simple foo 1 text foo 0 {}}
test parse-2.3 {Tcl_ParseCommand procedure, backslash-newline in comments} testparser {
    testparser " # foo bar\\\ncomment on continuation line\nfoo" 0
} {\#\ foo\ bar\\\ncomment\ on\ continuation\ line\n foo 1 simple foo 1 text foo 0 {}}
test parse-2.4 {Tcl_ParseCommand procedure, missing continuation line in comment} testparser {
    testparser "#   \\\n" 0
} {\#\ \ \ \\\n {} 0 {}}
test parse-2.5 {Tcl_ParseCommand procedure, eof in comment} testparser {
    testparser " # foo bar\nfoo" 8
} {{# foo b} {} 0 {ar
foo}}

test parse-3.1 {Tcl_ParseCommand procedure, parsing words, skipping space} testparser {
    testparser "foo  bar\t\tx" 0
} {- {foo  bar		x} 3 simple foo 1 text foo 0 simple bar 1 text bar 0 simple x 1 text x 0 {}}
test parse-3.2 {Tcl_ParseCommand procedure, missing continuation line in leading space} testparser {
    testparser "abc  \\\n" 0
} {- abc\ \ \\\n 1 simple abc 1 text abc 0 {}}
test parse-3.3 {Tcl_ParseCommand procedure, parsing words, command ends in space} testparser {
    testparser "foo  ;  bar x" 0
} {- {foo  ;} 1 simple foo 1 text foo 0 {  bar x}}
test parse-3.4 {Tcl_ParseCommand procedure, parsing words, command ends in space} testparser {
    testparser "foo       " 5
} {- {foo  } 1 simple foo 1 text foo 0 {     }}
test parse-3.5 {Tcl_ParseCommand procedure, quoted words} testparser {
    testparser {foo "a b c" d "efg";} 0
} {- {foo "a b c" d "efg";} 4 simple foo 1 text foo 0 simple {"a b c"} 1 text {a b c} 0 simple d 1 text d 0 simple {"efg"} 1 text efg 0 {}}
test parse-3.6 {Tcl_ParseCommand procedure, words in braces} testparser {
    testparser {foo {a $b [concat foo]} {c d}} 0
} {- {foo {a $b [concat foo]} {c d}} 3 simple foo 1 text foo 0 simple {{a $b [concat foo]}} 1 text {a $b [concat foo]} 0 simple {{c d}} 1 text {c d} 0 {}}
test parse-3.7 {Tcl_ParseCommand procedure, error in unquoted word} testparser {
    list [catch {testparser "foo \$\{abc" 0} msg] $msg $errorInfo
} {1 {missing close-brace for variable name} missing\ close-brace\ for\ variable\ name\n\ \ \ \ (remainder\ of\ script:\ \"\{abc\")\n\ \ \ \ invoked\ from\ within\n\"testparser\ \"foo\ \\\$\\\{abc\"\ 0\"}

test parse-4.1 {Tcl_ParseCommand procedure, simple words} testparser {
    testparser {foo} 0
} {- foo 1 simple foo 1 text foo 0 {}}
test parse-4.2 {Tcl_ParseCommand procedure, simple words} testparser {
    testparser {{abc}} 0
} {- {{abc}} 1 simple {{abc}} 1 text abc 0 {}}
test parse-4.3 {Tcl_ParseCommand procedure, simple words} testparser {
    testparser {"c d"} 0
} {- {"c d"} 1 simple {"c d"} 1 text {c d} 0 {}}
test parse-4.4 {Tcl_ParseCommand procedure, simple words} testparser {
    testparser {x$d} 0
} {- {x$d} 1 word {x$d} 3 text x 0 variable {$d} 1 text d 0 {}}
test parse-4.5 {Tcl_ParseCommand procedure, simple words} testparser {
    testparser {"a [foo] b"} 0
} {- {"a [foo] b"} 1 word {"a [foo] b"} 3 text {a } 0 command {[foo]} 0 text { b} 0 {}}
test parse-4.6 {Tcl_ParseCommand procedure, simple words} testparser {
    testparser {$x} 0
} {- {$x} 1 word {$x} 2 variable {$x} 1 text x 0 {}}

test parse-5.1 {Tcl_ParseCommand procedure, backslash-newline terminates word} testparser {
    testparser "{abc}\\\n" 0
} {- \{abc\}\\\n 1 simple {{abc}} 1 text abc 0 {}}
test parse-5.2 {Tcl_ParseCommand procedure, backslash-newline terminates word} testparser {
    testparser "foo\\\nbar" 0
} {- foo\\\nbar 2 simple foo 1 text foo 0 simple bar 1 text bar 0 {}}
test parse-5.3 {Tcl_ParseCommand procedure, word terminator is command terminator} testparser {
    testparser "foo\n bar" 0
} {- {foo
} 1 simple foo 1 text foo 0 { bar}}
test parse-5.4 {Tcl_ParseCommand procedure, word terminator is command terminator} testparser {
    testparser "foo; bar" 0
} {- {foo;} 1 simple foo 1 text foo 0 { bar}}
test parse-5.5 {Tcl_ParseCommand procedure, word terminator is end of string} testparser {
    testparser "\"foo\" bar" 5
} {- {"foo"} 1 simple {"foo"} 1 text foo 0 { bar}}
test parse-5.6 {Tcl_ParseCommand procedure, junk after close quote} testparser {
    list [catch {testparser {foo "bar"x} 0} msg] $msg $errorInfo
} {1 {extra characters after close-quote} {extra characters after close-quote
    (remainder of script: "x")
    invoked from within
"testparser {foo "bar"x} 0"}}
test parse-5.7 {Tcl_ParseCommand procedure, backslash-newline after close quote} testparser {
    testparser "foo \"bar\"\\\nx" 0
} {- foo\ \"bar\"\\\nx 3 simple foo 1 text foo 0 simple {"bar"} 1 text bar 0 simple x 1 text x 0 {}}
test parse-5.8 {Tcl_ParseCommand procedure, junk after close brace} testparser {
    list [catch {testparser {foo {bar}x} 0} msg] $msg $errorInfo
} {1 {extra characters after close-brace} {extra characters after close-brace
    (remainder of script: "x")
    invoked from within
"testparser {foo {bar}x} 0"}}
test parse-5.9 {Tcl_ParseCommand procedure, backslash-newline after close brace} testparser {
    testparser "foo {bar}\\\nx" 0
} {- foo\ \{bar\}\\\nx 3 simple foo 1 text foo 0 simple {{bar}} 1 text bar 0 simple x 1 text x 0 {}}
test parse-5.10 {Tcl_ParseCommand procedure, multiple deletion of non-static buffer} testparser {
    # This test is designed to catch bug 1681.
    list [catch {testparser "a \"\\1\\2\\3\\4\\5\\6\\7\\8\\9\\1\\2\\3\\4\\5\\6\\7\\8" 0} msg] $msg $errorInfo
} "1 {missing \"} {missing \"
    (remainder of script: \"\"\\1\\2\\3\\4\\5\\6\\7\\8\\9\\1\\2\\3\\4\\5\\6\\7\\8\")
    invoked from within
\"testparser \"a \\\"\\\\1\\\\2\\\\3\\\\4\\\\5\\\\6\\\\7\\\\8\\\\9\\\\1\\\\2\\\\3\\\\4\\\\5\\\\6\\\\7\\\\8\" 0\"}"

test parse-5.11 {Tcl_ParseCommand: {expand} parsing} testparser {
    testparser {{expan}} 0
} {- {{expan}} 1 simple {{expan}} 1 text expan 0 {}}
test parse-5.12 {Tcl_ParseCommand: {expand} parsing} -constraints {
    testparser
} -body {
    testparser {{expan}x} 0
} -returnCodes error  -result {extra characters after close-brace}
test parse-5.13 {Tcl_ParseCommand: {expand} parsing} testparser {
    testparser {{expandy}} 0
} {- {{expandy}} 1 simple {{expandy}} 1 text expandy 0 {}}
test parse-5.14 {Tcl_ParseCommand: {expand} parsing} -constraints {
    testparser
} -body {
    testparser {{expandy}x} 0
} -returnCodes error  -result {extra characters after close-brace}
test parse-5.15 {Tcl_ParseCommand: {expand} parsing} -constraints {
    testparser
} -body {
    testparser {{expand}{123456}x} 0
} -returnCodes error  -result {extra characters after close-brace}
test parse-5.16 {Tcl_ParseCommand: {expand} parsing} testparser {
    testparser {{123456\
			}} 0
} {- {{123456 }} 1 simple {{123456 }} 1 text {123456 } 0 {}}
test parse-5.17 {Tcl_ParseCommand: {expand} parsing} -constraints {
    testparser
} -body {
    testparser {{123456\
			}x} 0
} -returnCodes error  -result {extra characters after close-brace}
test parse-5.18 {Tcl_ParseCommand: {expand} parsing} testparser {
    testparser {{expand\
			}} 0
} {- {{expand }} 1 simple {{expand }} 1 text {expand } 0 {}}
test parse-5.19 {Tcl_ParseCommand: {expand} parsing} -constraints {
    testparser
} -body {
    testparser {{expand\
			}x} 0
} -returnCodes error  -result {extra characters after close-brace}
test parse-5.20 {Tcl_ParseCommand: {expand} parsing} testparser {
    testparser {{123456}} 0
} {- {{123456}} 1 simple {{123456}} 1 text 123456 0 {}}
test parse-5.21 {Tcl_ParseCommand: {expand} parsing} -constraints {
    testparser
} -body {
    testparser {{123456}x} 0
} -returnCodes error  -result {extra characters after close-brace}
test parse-5.22 {Tcl_ParseCommand: {expand} parsing} testparser {
    testparser {{expand}} 0
} {- {{expand}} 1 simple {{expand}} 1 text expand 0 {}}
test parse-5.23 {Tcl_ParseCommand: {expand} parsing} testparser {
    testparser {{expand} } 0
} {- {{expand} } 1 simple {{expand}} 1 text expand 0 {}}
test parse-5.24 {Tcl_ParseCommand: {expand} parsing} testparser {
    testparser {{expand}x} 0
} {- {{expand}x} 1 expand {{expand}x} 1 text x 0 {}}
test parse-5.25 {Tcl_ParseCommand: {expand} parsing} testparser {
    testparser {{expand}
} 0
} {- {{expand}
} 1 simple {{expand}} 1 text expand 0 {}}
test parse-5.26 {Tcl_ParseCommand: {expand} parsing} testparser {
    testparser {{expand};} 0
} {- {{expand};} 1 simple {{expand}} 1 text expand 0 {}}
test parse-5.27 {Tcl_ParseCommand: {expand} parsing} testparser {
    testparser "{expand}\\\n foo bar" 0
} {- \{expand\}\\\n\ foo\ bar 3 simple {{expand}} 1 text expand 0 simple foo 1 text foo 0 simple bar 1 text bar 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 {}}
test parse-6.3 {ParseTokens procedure, variable reference} testparser {
    testparser {abc$x.e $y(z)} 0
} {- {abc$x.e $y(z)} 2 word {abc$x.e} 4 text abc 0 variable {$x} 1 text x 0 text .e 0 word {$y(z)} 3 variable {$y(z)} 2 text y 0 text z 0 {}}
test parse-6.4 {ParseTokens procedure, variable reference} testparser {
    list [catch {testparser {$x([a )} 0} msg] $msg
} {1 {missing close-bracket}}
test parse-6.5 {ParseTokens procedure, command substitution} testparser {
    testparser {[foo $x bar]z} 0
} {- {[foo $x bar]z} 1 word {[foo $x bar]z} 2 command {[foo $x bar]} 0 text z 0 {}}
test parse-6.6 {ParseTokens procedure, command substitution} testparser {
    testparser {[foo \] [a b]]} 0
} {- {[foo \] [a b]]} 1 word {[foo \] [a b]]} 1 command {[foo \] [a b]]} 0 {}}
test parse-6.7 {ParseTokens procedure, error in command substitution} testparser {
    list [catch {testparser {a [b {}c d] e} 0} msg] $msg $errorInfo
} {1 {extra characters after close-brace} {extra characters after close-brace
    (remainder of script: "c d] e")
    invoked from within
"testparser {a [b {}c d] e} 0"}}
test parse-6.8 {ParseTokens procedure, error in command substitution} {
    info complete {a [b {}c d]}
} {1}
test parse-6.9 {ParseTokens procedure, error in command substitution} {
    info complete {a [b "c d}
} {0}
test parse-6.10 {ParseTokens procedure, incomplete sub-command} {
    info complete {puts [
	expr 1+1
	#this is a comment ]}
} {0}
test parse-6.11 {ParseTokens procedure, memory allocation for big nested command} testparser {
    testparser {[$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b)]} 0
} {- {[$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b)]} 1 word {[$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b)]} 1 command {[$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b)]} 0 {}}
test parse-6.12 {ParseTokens procedure, missing close bracket} testparser {
    list [catch {testparser {[foo $x bar} 0} msg] $msg $errorInfo
} {1 {missing close-bracket} {missing close-bracket
    (remainder of script: "[foo $x bar")
    invoked from within
"testparser {[foo $x bar} 0"}}
test parse-6.13 {ParseTokens procedure, backslash-newline without continuation line} testparser {
    list [catch {testparser "\"a b\\\n" 0} msg] $msg $errorInfo
} {1 {missing "} missing\ \"\n\ \ \ \ (remainder\ of\ script:\ \"\"a\ b\\\n\")\n\ \ \ \ invoked\ from\ within\n\"testparser\ \"\\\"a\ b\\\\\\n\"\ 0\"}
test parse-6.14 {ParseTokens procedure, backslash-newline} testparser {
    testparser "b\\\nc" 0
} {- b\\\nc 2 simple b 1 text b 0 simple c 1 text c 0 {}}
test parse-6.15 {ParseTokens procedure, backslash-newline} testparser {
    testparser "\"b\\\nc\"" 0
} {- \"b\\\nc\" 1 word \"b\\\nc\" 3 text b 0 backslash \\\n 0 text c 0 {}}
test parse-6.16 {ParseTokens procedure, backslash substitution} testparser {
    testparser {\n\a\x7f} 0
} {- {\n\a\x7f} 1 word {\n\a\x7f} 3 backslash {\n} 0 backslash {\a} 0 backslash {\x7f} 0 {}}
test parse-6.17 {ParseTokens procedure, null characters} testparser {
    testparser [bytestring "foo\0zz"] 0
} "- [bytestring foo\0zz] 1 word [bytestring foo\0zz] 3 text foo 0 text [bytestring \0] 0 text zz 0 {}"
test parse-6.18 {ParseTokens procedure, seek past numBytes for close-bracket} testparser {
    # Test for Bug 681841
    list [catch {testparser {[a]} 2} msg] $msg
} {1 {missing close-bracket}}

test parse-7.1 {Tcl_FreeParse and ExpandTokenArray procedures} testparser {
    testparser {$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) } 0
} {- {$a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) $a(b) } 16 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 word {$a(b)} 3 variable {$a(b)} 2 text a 0 text b 0 {}}

test parse-8.1 {Tcl_EvalObjv procedure} testevalobjv {
    testevalobjv 0 concat this is a test
} {this is a test}
test parse-8.2 {Tcl_EvalObjv procedure, unknown commands} testevalobjv {
    rename ::unknown unknown.old
    set x [catch {testevalobjv 10 asdf poiu} msg]
    rename unknown.old ::unknown
    list $x $msg
} {1 {invalid command name "asdf"}}
test parse-8.3 {Tcl_EvalObjv procedure, unknown commands} testevalobjv {
    rename ::unknown unknown.old
    proc ::unknown args {
	return "unknown $args"
    }
    set x [catch {testevalobjv 0 asdf poiu} msg]
    rename ::unknown {}
    rename unknown.old ::unknown
    list $x $msg
} {0 {unknown asdf poiu}}
test parse-8.4 {Tcl_EvalObjv procedure, unknown commands} testevalobjv {
    rename ::unknown unknown.old
    proc ::unknown args {
	error "I don't like that command"
    }
    set x [catch {testevalobjv 0 asdf poiu} msg]
    rename ::unknown {}
    rename unknown.old ::unknown
    list $x $msg
} {1 {I don't like that command}}
test parse-8.5 {Tcl_EvalObjv procedure, command traces} {testevalobjv testcmdtrace} {
    testevalobjv 0 set x 123
    testcmdtrace tracetest {testevalobjv 0 set x $x}
} {{testevalobjv 0 set x $x} {testevalobjv 0 set x 123} {set x 123} {set x 123}}
test parse-8.7 {Tcl_EvalObjv procedure, TCL_EVAL_GLOBAL flag} -constraints {
    testevalobjv
} -setup {
    proc x {} {
	set y 23
	set z [testevalobjv 1 set y]
	return [list $z $y]
    }
    set ::y 16
} -cleanup {
    unset ::y
} -body {
    x
} -result {16 23}
test parse-8.8 {Tcl_EvalObjv procedure, async handlers} -constraints {
    testevalobjv testasync
} -setup {
    variable ::aresult
    variable ::acode
    proc async1 {result code} {
	variable ::aresult 
	variable ::acode
	set aresult $result
	set acode $code
	return "new result"
    }
    set handler1 [testasync create async1]
    set aresult xxx
    set acode yyy
} -cleanup {
    testasync delete
} -body {
    list [testevalobjv 0 testasync mark $handler1 original 0] $acode $aresult
} -result {{new result} 0 original}
test parse-8.9 {Tcl_EvalObjv procedure, exceptional return} testevalobjv {
    list [catch {testevalobjv 0 error message} msg] $msg
} {1 message}

test parse-9.1 {Tcl_LogCommandInfo, line numbers} testevalex {
    catch {unset x}
    list [catch {testevalex {for {} 1 {} {


	# asdf
	set x
    }}}] $errorInfo
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
    invoked from within
"testevalex {for {} 1 {} {


	# asdf
	set x
    }}"}}
test parse-9.2 {Tcl_LogCommandInfo, truncating long commands} {
    list [testevalex {catch {set a b 111111111 222222222 333333333 444444444 555555555 666666666 777777777 888888888 999999999 000000000 aaaaaaaaa bbbbbbbbb ccccccccc ddddddddd eeeeeeeee fffffffff ggggggggg}}] $errorInfo
} {1 {wrong # args: should be "set varName ?newValue?"
    while executing
"set a b 111111111 222222222 333333333 444444444 555555555 666666666 777777777 888888888 999999999 000000000 aaaaaaaaa bbbbbbbbb ccccccccc ddddddddd ee..."}}

test parse-10.1 {Tcl_EvalTokens, simple text} {
    testevalex {concat test}
} {test}
test parse-10.2 {Tcl_EvalTokens, backslash sequences} {
    testevalex {concat test\063\062test}
} {test32test}
test parse-10.3 {Tcl_EvalTokens, nested commands} {
    testevalex {concat [expr 2 + 6]}
} {8}
test parse-10.4 {Tcl_EvalTokens, nested commands} {
    catch {unset a}
    list [catch {testevalex {concat xxx[expr $a]}} msg] $msg
} {1 {can't read "a": no such variable}}
test parse-10.5 {Tcl_EvalTokens, simple variables} {
    set a hello
    testevalex {concat $a}
} {hello}
test parse-10.6 {Tcl_EvalTokens, array variables} {
    catch {unset a}
    set a(12) 46
    testevalex {concat $a(12)}
} {46}
test parse-10.7 {Tcl_EvalTokens, array variables} {
    catch {unset a}
    set a(12) 46
    testevalex {concat $a(1[expr 3 - 1])}
} {46}
test parse-10.8 {Tcl_EvalTokens, array variables} {
    catch {unset a}
    list [catch {testevalex {concat $x($a)}} msg] $msg
} {1 {can't read "a": no such variable}}
test parse-10.9 {Tcl_EvalTokens, array variables} {
    catch {unset a}
    list [catch {testevalex {concat xyz$a(1)}} msg] $msg
} {1 {can't read "a(1)": no such variable}}
test parse-10.10 {Tcl_EvalTokens, object values} {
    set a 123
    testevalex {concat $a}
} {123}
test parse-10.11 {Tcl_EvalTokens, object values} {
    set a 123
    testevalex {concat $a$a$a}
} {123123123}
test parse-10.12 {Tcl_EvalTokens, object values} {
    testevalex {concat [expr 2][expr 4][expr 6]}
} {246}
test parse-10.13 {Tcl_EvalTokens, string values} {
    testevalex {concat {a" b"}}
} {a" b"}
test parse-10.14 {Tcl_EvalTokens, string values} {
    set a 111
    testevalex {concat x$a.$a.$a}
} {x111.111.111}

test parse-11.1 {Tcl_EvalEx, TCL_EVAL_GLOBAL flag} {


    proc x {} {
	set y 777
	set z [testevalex "set y" global]
	return [list $z $y]
    }
    catch {unset y}

    set y 321

    x
} {321 777}
test parse-11.2 {Tcl_EvalEx, error while parsing} {
    list [catch {testevalex {concat "abc}} msg] $msg
} {1 {missing "}}
test parse-11.3 {Tcl_EvalEx, error while collecting words} {
    catch {unset a}
    list [catch {testevalex {concat xyz $a}} msg] $msg
} {1 {can't read "a": no such variable}}
test parse-11.4 {Tcl_EvalEx, error in Tcl_EvalObjv call} {
    catch {unset a}
    list [catch {testevalex {_bogus_ a b c d}} msg] $msg
} {1 {invalid command name "_bogus_"}}
test parse-11.5 {Tcl_EvalEx, exceptional return} {
    list [catch {testevalex {break}} msg] $msg
} {3 {}}
test parse-11.6 {Tcl_EvalEx, freeing memory} {
    testevalex {concat 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}
} {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}
test parse-11.7 {Tcl_EvalEx, multiple commands in script} {
    list [testevalex {set a b; set c d}] $a $c
} {d b d}
test parse-11.8 {Tcl_EvalEx, multiple commands in script} {
    list [testevalex {
	set a b
	set c d
    }] $a $c
} {d b d}
test parse-11.9 {Tcl_EvalEx, freeing memory after error} {
    catch {unset a}
    list [catch {testevalex {concat 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 $a}} msg] $msg
} {1 {can't read "a": no such variable}}
test parse-11.10 {Tcl_EvalTokens, empty commands} {
    testevalex {concat xyz;   }
} {xyz}
test parse-11.11 {Tcl_EvalTokens, empty commands} {
    testevalex "concat abc; ; # this is a comment\n"
} {abc}
test parse-11.12 {Tcl_EvalTokens, empty commands} {
    testevalex {}
} {}

test parse-12.1 {Tcl_ParseVarName procedure, initialization} {
    list [catch {testparsevarname {$a([first second])} 8 0} msg] $msg
} {1 {missing close-bracket}}
test parse-12.2 {Tcl_ParseVarName procedure, initialization} {
    testparsevarname {$a([first second])} 0 0
} {- {} 0 variable {$a([first second])} 2 text a 0 command {[first second]} 0 {}}
test parse-12.3 {Tcl_ParseVarName procedure, initialization} {
    list [catch {testparsevarname {$abcd} 3 0} msg] $msg
} {0 {- {} 0 variable {$ab} 1 text ab 0 cd}}
test parse-12.4 {Tcl_ParseVarName procedure, initialization} {
    testparsevarname {$abcd} 0 0
} {- {} 0 variable {$abcd} 1 text abcd 0 {}}
test parse-12.5 {Tcl_ParseVarName procedure, just a dollar sign} {
    testparsevarname {$abcd} 1 0
} {- {} 0 text {$} 0 abcd}
test parse-12.6 {Tcl_ParseVarName procedure, braced variable name} {
    testparser {${..[]b}cd} 0
} {- {${..[]b}cd} 1 word {${..[]b}cd} 3 variable {${..[]b}} 1 text {..[]b} 0 text cd 0 {}}
test parse-12.7 {Tcl_ParseVarName procedure, braced variable name} {
    testparser "\$\{\{\} " 0
} {- \$\{\{\}\  1 word \$\{\{\} 2 variable \$\{\{\} 1 text \{ 0 {}}
test parse-12.8 {Tcl_ParseVarName procedure, missing close brace} {
    list [catch {testparser "$\{abc" 0} msg] $msg $errorInfo
} {1 {missing close-brace for variable name} missing\ close-brace\ for\ variable\ name\n\ \ \ \ (remainder\ of\ script:\ \"\{abc\")\n\ \ \ \ invoked\ from\ within\n\"testparser\ \"\$\\\{abc\"\ 0\"}
test parse-12.9 {Tcl_ParseVarName procedure, missing close brace} {
    list [catch {testparsevarname {${bcd}} 4 0} msg] $msg
} {1 {missing close-brace for variable name}}
test parse-12.10 {Tcl_ParseVarName procedure, missing close brace} {
    list [catch {testparsevarname {${bc}} 4 0} msg] $msg
} {1 {missing close-brace for variable name}}
test parse-12.11 {Tcl_ParseVarName procedure, simple variable name} {
    testparser {$az_AZ.} 0
} {- {$az_AZ.} 1 word {$az_AZ.} 3 variable {$az_AZ} 1 text az_AZ 0 text . 0 {}}
test parse-12.12 {Tcl_ParseVarName procedure, simple variable name} {
    testparser {$abcdefg} 4
} {- {$abc} 1 word {$abc} 2 variable {$abc} 1 text abc 0 defg}
test parse-12.13 {Tcl_ParseVarName procedure, simple variable name with ::} {
    testparser {$xyz::ab:c} 0
} {- {$xyz::ab:c} 1 word {$xyz::ab:c} 3 variable {$xyz::ab} 1 text xyz::ab 0 text :c 0 {}}
test parse-12.14 {Tcl_ParseVarName procedure, variable names with many colons} {
    testparser {$xyz:::::c} 0
} {- {$xyz:::::c} 1 word {$xyz:::::c} 2 variable {$xyz:::::c} 1 text xyz:::::c 0 {}}
test parse-12.15 {Tcl_ParseVarName procedure, : vs. ::} {
    testparsevarname {$ab:cd} 0 0
} {- {} 0 variable {$ab} 1 text ab 0 :cd}
test parse-12.16 {Tcl_ParseVarName procedure, eof in ::} {
    testparsevarname {$ab::cd} 4 0
} {- {} 0 variable {$ab} 1 text ab 0 ::cd}
test parse-12.17 {Tcl_ParseVarName procedure, eof in ::} {
    testparsevarname {$ab:::cd} 5 0
} {- {} 0 variable {$ab::} 1 text ab:: 0 :cd}
test parse-12.18 {Tcl_ParseVarName procedure, no variable name} {
    testparser {$$ $.} 0
} {- {$$ $.} 2 word {$$} 2 text {$} 0 text {$} 0 word {$.} 2 text {$} 0 text . 0 {}}
test parse-12.19 {Tcl_ParseVarName procedure, EOF before (} {
    testparsevarname {$ab(cd)} 3 0
} {- {} 0 variable {$ab} 1 text ab 0 (cd)}
test parse-12.20 {Tcl_ParseVarName procedure, array reference} {
    testparser {$x(abc)} 0
} {- {$x(abc)} 1 word {$x(abc)} 3 variable {$x(abc)} 2 text x 0 text abc 0 {}}
test parse-12.21 {Tcl_ParseVarName procedure, array reference} {
    testparser {$x(ab$cde[foo bar])} 0
} {- {$x(ab$cde[foo bar])} 1 word {$x(ab$cde[foo bar])} 6 variable {$x(ab$cde[foo bar])} 5 text x 0 text ab 0 variable {$cde} 1 text cde 0 command {[foo bar]} 0 {}}
test parse-12.22 {Tcl_ParseVarName procedure, array reference} {
    testparser {$x([cmd arg]zz)} 0
} {- {$x([cmd arg]zz)} 1 word {$x([cmd arg]zz)} 4 variable {$x([cmd arg]zz)} 3 text x 0 command {[cmd arg]} 0 text zz 0 {}}
test parse-12.23 {Tcl_ParseVarName procedure, missing close paren in array reference} {
    list [catch {testparser {$x(poiu} 0} msg] $msg $errorInfo
} {1 {missing )} {missing )
    (remainder of script: "(poiu")
    invoked from within
"testparser {$x(poiu} 0"}}
test parse-12.24 {Tcl_ParseVarName procedure, missing close paren in array reference} {
    list [catch {testparsevarname {$ab(cd)} 6 0} msg] $msg $errorInfo
} {1 {missing )} {missing )
    (remainder of script: "(cd)")
    invoked from within
"testparsevarname {$ab(cd)} 6 0"}}
test parse-12.25 {Tcl_ParseVarName procedure, nested array reference} {
    testparser {$x(a$y(b$z))} 0
} {- {$x(a$y(b$z))} 1 word {$x(a$y(b$z))} 8 variable {$x(a$y(b$z))} 7 text x 0 text a 0 variable {$y(b$z)} 4 text y 0 text b 0 variable {$z} 1 text z 0 {}}

test parse-13.1 {Tcl_ParseVar procedure} {
    set abc 24
    testparsevar {$abc.fg}
} {24 .fg}
test parse-13.2 {Tcl_ParseVar procedure, no variable name} {
    testparsevar {$}
} {{$} {}}
test parse-13.3 {Tcl_ParseVar procedure, no variable name} {
    testparsevar {$.123}
} {{$} .123}
test parse-13.4 {Tcl_ParseVar procedure, error looking up variable} {
    catch {unset abc}
    list [catch {testparsevar {$abc}} msg] $msg
} {1 {can't read "abc": no such variable}}
test parse-13.5 {Tcl_ParseVar procedure, error looking up variable} {
    catch {unset abc}
    list [catch {testparsevar {$abc([bogus x y z])}} msg] $msg
} {1 {invalid command name "bogus"}}

test parse-14.1 {Tcl_ParseBraces procedure, computing string length} {
    testparser [bytestring "foo\0 bar"] -1
} {- foo 1 simple foo 1 text foo 0 {}}
test parse-14.2 {Tcl_ParseBraces procedure, computing string length} {
    testparser "foo bar" -1
} {- {foo bar} 2 simple foo 1 text foo 0 simple bar 1 text bar 0 {}}
test parse-14.3 {Tcl_ParseBraces procedure, words in braces} {
    testparser {foo {a $b [concat foo]} {c d}} 0
} {- {foo {a $b [concat foo]} {c d}} 3 simple foo 1 text foo 0 simple {{a $b [concat foo]}} 1 text {a $b [concat foo]} 0 simple {{c d}} 1 text {c d} 0 {}}
test parse-14.4 {Tcl_ParseBraces procedure, empty nested braces} {
    testparser {foo {{}}} 0
} {- {foo {{}}} 2 simple foo 1 text foo 0 simple {{{}}} 1 text {{}} 0 {}}
test parse-14.5 {Tcl_ParseBraces procedure, nested braces} {
    testparser {foo {{a {b} c} {} {d e}}} 0
} {- {foo {{a {b} c} {} {d e}}} 2 simple foo 1 text foo 0 simple {{{a {b} c} {} {d e}}} 1 text {{a {b} c} {} {d e}} 0 {}}
test parse-14.6 {Tcl_ParseBraces procedure, backslashes in words in braces} {
    testparser "foo {a \\n\\\{}" 0
} {- {foo {a \n\{}} 2 simple foo 1 text foo 0 simple {{a \n\{}} 1 text {a \n\{} 0 {}}
test parse-14.7 {Tcl_ParseBraces procedure, missing continuation line in braces} {
    list [catch {testparser "\{abc\\\n" 0} msg] $msg $errorInfo
} {1 {missing close-brace} missing\ close-brace\n\ \ \ \ (remainder\ of\ script:\ \"\{abc\\\n\")\n\ \ \ \ invoked\ from\ within\n\"testparser\ \"\\\{abc\\\\\\n\"\ 0\"}
test parse-14.8 {Tcl_ParseBraces procedure, backslash-newline in braces} {
    testparser "foo {\\\nx}" 0
} {- foo\ \{\\\nx\} 2 simple foo 1 text foo 0 word \{\\\nx\} 2 backslash \\\n 0 text x 0 {}}
test parse-14.9 {Tcl_ParseBraces procedure, backslash-newline in braces} {
    testparser "foo {a \\\n   b}" 0
} {- foo\ \{a\ \\\n\ \ \ b\} 2 simple foo 1 text foo 0 word \{a\ \\\n\ \ \ b\} 3 text {a } 0 backslash \\\n\ \ \  0 text b 0 {}}
test parse-14.10 {Tcl_ParseBraces procedure, backslash-newline in braces} {
    testparser "foo {xyz\\\n }" 0
} {- foo\ \{xyz\\\n\ \} 2 simple foo 1 text foo 0 word \{xyz\\\n\ \} 2 text xyz 0 backslash \\\n\  0 {}}
test parse-14.11 {Tcl_ParseBraces procedure, empty braced string} {
    testparser {foo {}} 0
} {- {foo {}} 2 simple foo 1 text foo 0 simple {{}} 1 text {} 0 {}}
test parse-14.12 {Tcl_ParseBraces procedure, missing close brace} {
    list [catch {testparser "foo \{xy\\\nz" 0} msg] $msg $errorInfo
} {1 {missing close-brace} missing\ close-brace\n\ \ \ \ (remainder\ of\ script:\ \"\{xy\\\nz\")\n\ \ \ \ invoked\ from\ within\n\"testparser\ \"foo\ \\\{xy\\\\\\nz\"\ 0\"}

test parse-15.1 {Tcl_ParseQuotedString procedure, computing string length} {
    testparser [bytestring "foo\0 bar"] -1
} {- foo 1 simple foo 1 text foo 0 {}}
test parse-15.2 {Tcl_ParseQuotedString procedure, computing string length} {
    testparser "foo bar" -1
} {- {foo bar} 2 simple foo 1 text foo 0 simple bar 1 text bar 0 {}}
test parse-15.3 {Tcl_ParseQuotedString procedure, word is quoted string} {
    testparser {foo "a b c" d "efg";} 0
} {- {foo "a b c" d "efg";} 4 simple foo 1 text foo 0 simple {"a b c"} 1 text {a b c} 0 simple d 1 text d 0 simple {"efg"} 1 text efg 0 {}}
test parse-15.4 {Tcl_ParseQuotedString procedure, garbage after quoted string} {
    list [catch {testparser {foo "a b c"d} 0} msg] $msg $errorInfo
} {1 {extra characters after close-quote} {extra characters after close-quote
    (remainder of script: "d")
    invoked from within
"testparser {foo "a b c"d} 0"}}

test parse-15.5 {CommandComplete procedure} {







|





|


|


|


|



|



|




|




|



|



|



|



|


|


|




|
>
>





|
>
|
>

|
|


|



|



|


|


|


|





|



|


|


|



|


|


|


|


|


|


|


|


|


|


|


|


|


|


|


|


|


|


|


|


|


|


|





|





|



|



|


|


|



|




|


|


|


|


|


|


|


|


|


|


|


|



|


|


|


|







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
    invoked from within
"testevalex {for {} 1 {} {


	# asdf
	set x
    }}"}}
test parse-9.2 {Tcl_LogCommandInfo, truncating long commands} testevalex {
    list [testevalex {catch {set a b 111111111 222222222 333333333 444444444 555555555 666666666 777777777 888888888 999999999 000000000 aaaaaaaaa bbbbbbbbb ccccccccc ddddddddd eeeeeeeee fffffffff ggggggggg}}] $errorInfo
} {1 {wrong # args: should be "set varName ?newValue?"
    while executing
"set a b 111111111 222222222 333333333 444444444 555555555 666666666 777777777 888888888 999999999 000000000 aaaaaaaaa bbbbbbbbb ccccccccc ddddddddd ee..."}}

test parse-10.1 {Tcl_EvalTokens, simple text} testevalex {
    testevalex {concat test}
} {test}
test parse-10.2 {Tcl_EvalTokens, backslash sequences} testevalex {
    testevalex {concat test\063\062test}
} {test32test}
test parse-10.3 {Tcl_EvalTokens, nested commands} testevalex {
    testevalex {concat [expr 2 + 6]}
} {8}
test parse-10.4 {Tcl_EvalTokens, nested commands} testevalex {
    catch {unset a}
    list [catch {testevalex {concat xxx[expr $a]}} msg] $msg
} {1 {can't read "a": no such variable}}
test parse-10.5 {Tcl_EvalTokens, simple variables} testevalex {
    set a hello
    testevalex {concat $a}
} {hello}
test parse-10.6 {Tcl_EvalTokens, array variables} testevalex {
    catch {unset a}
    set a(12) 46
    testevalex {concat $a(12)}
} {46}
test parse-10.7 {Tcl_EvalTokens, array variables} testevalex {
    catch {unset a}
    set a(12) 46
    testevalex {concat $a(1[expr 3 - 1])}
} {46}
test parse-10.8 {Tcl_EvalTokens, array variables} testevalex {
    catch {unset a}
    list [catch {testevalex {concat $x($a)}} msg] $msg
} {1 {can't read "a": no such variable}}
test parse-10.9 {Tcl_EvalTokens, array variables} testevalex {
    catch {unset a}
    list [catch {testevalex {concat xyz$a(1)}} msg] $msg
} {1 {can't read "a(1)": no such variable}}
test parse-10.10 {Tcl_EvalTokens, object values} testevalex {
    set a 123
    testevalex {concat $a}
} {123}
test parse-10.11 {Tcl_EvalTokens, object values} testevalex {
    set a 123
    testevalex {concat $a$a$a}
} {123123123}
test parse-10.12 {Tcl_EvalTokens, object values} testevalex {
    testevalex {concat [expr 2][expr 4][expr 6]}
} {246}
test parse-10.13 {Tcl_EvalTokens, string values} testevalex {
    testevalex {concat {a" b"}}
} {a" b"}
test parse-10.14 {Tcl_EvalTokens, string values} testevalex {
    set a 111
    testevalex {concat x$a.$a.$a}
} {x111.111.111}

test parse-11.1 {Tcl_EvalEx, TCL_EVAL_GLOBAL flag} -constraints {
    testevalex
} -setup {
    proc x {} {
	set y 777
	set z [testevalex "set y" global]
	return [list $z $y]
    }
    set ::y 321
} -cleanup {
    unset ::y
} -body {
    x
} -result {321 777}
test parse-11.2 {Tcl_EvalEx, error while parsing} testevalex {
    list [catch {testevalex {concat "abc}} msg] $msg
} {1 {missing "}}
test parse-11.3 {Tcl_EvalEx, error while collecting words} testevalex {
    catch {unset a}
    list [catch {testevalex {concat xyz $a}} msg] $msg
} {1 {can't read "a": no such variable}}
test parse-11.4 {Tcl_EvalEx, error in Tcl_EvalObjv call} testevalex {
    catch {unset a}
    list [catch {testevalex {_bogus_ a b c d}} msg] $msg
} {1 {invalid command name "_bogus_"}}
test parse-11.5 {Tcl_EvalEx, exceptional return} testevalex {
    list [catch {testevalex {break}} msg] $msg
} {3 {}}
test parse-11.6 {Tcl_EvalEx, freeing memory} testevalex {
    testevalex {concat 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}
} {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}
test parse-11.7 {Tcl_EvalEx, multiple commands in script} testevalex {
    list [testevalex {set a b; set c d}] $a $c
} {d b d}
test parse-11.8 {Tcl_EvalEx, multiple commands in script} testevalex {
    list [testevalex {
	set a b
	set c d
    }] $a $c
} {d b d}
test parse-11.9 {Tcl_EvalEx, freeing memory after error} testevalex {
    catch {unset a}
    list [catch {testevalex {concat 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 $a}} msg] $msg
} {1 {can't read "a": no such variable}}
test parse-11.10 {Tcl_EvalTokens, empty commands} testevalex {
    testevalex {concat xyz;   }
} {xyz}
test parse-11.11 {Tcl_EvalTokens, empty commands} testevalex {
    testevalex "concat abc; ; # this is a comment\n"
} {abc}
test parse-11.12 {Tcl_EvalTokens, empty commands} testevalex {
    testevalex {}
} {}

test parse-12.1 {Tcl_ParseVarName procedure, initialization} testparsevarname {
    list [catch {testparsevarname {$a([first second])} 8 0} msg] $msg
} {1 {missing close-bracket}}
test parse-12.2 {Tcl_ParseVarName procedure, initialization} testparsevarname {
    testparsevarname {$a([first second])} 0 0
} {- {} 0 variable {$a([first second])} 2 text a 0 command {[first second]} 0 {}}
test parse-12.3 {Tcl_ParseVarName procedure, initialization} testparsevarname {
    list [catch {testparsevarname {$abcd} 3 0} msg] $msg
} {0 {- {} 0 variable {$ab} 1 text ab 0 cd}}
test parse-12.4 {Tcl_ParseVarName procedure, initialization} testparsevarname {
    testparsevarname {$abcd} 0 0
} {- {} 0 variable {$abcd} 1 text abcd 0 {}}
test parse-12.5 {Tcl_ParseVarName procedure, just a dollar sign} testparsevarname {
    testparsevarname {$abcd} 1 0
} {- {} 0 text {$} 0 abcd}
test parse-12.6 {Tcl_ParseVarName procedure, braced variable name} testparser {
    testparser {${..[]b}cd} 0
} {- {${..[]b}cd} 1 word {${..[]b}cd} 3 variable {${..[]b}} 1 text {..[]b} 0 text cd 0 {}}
test parse-12.7 {Tcl_ParseVarName procedure, braced variable name} testparser {
    testparser "\$\{\{\} " 0
} {- \$\{\{\}\  1 word \$\{\{\} 2 variable \$\{\{\} 1 text \{ 0 {}}
test parse-12.8 {Tcl_ParseVarName procedure, missing close brace} testparser {
    list [catch {testparser "$\{abc" 0} msg] $msg $errorInfo
} {1 {missing close-brace for variable name} missing\ close-brace\ for\ variable\ name\n\ \ \ \ (remainder\ of\ script:\ \"\{abc\")\n\ \ \ \ invoked\ from\ within\n\"testparser\ \"\$\\\{abc\"\ 0\"}
test parse-12.9 {Tcl_ParseVarName procedure, missing close brace} testparsevarname {
    list [catch {testparsevarname {${bcd}} 4 0} msg] $msg
} {1 {missing close-brace for variable name}}
test parse-12.10 {Tcl_ParseVarName procedure, missing close brace} testparsevarname {
    list [catch {testparsevarname {${bc}} 4 0} msg] $msg
} {1 {missing close-brace for variable name}}
test parse-12.11 {Tcl_ParseVarName procedure, simple variable name} testparser {
    testparser {$az_AZ.} 0
} {- {$az_AZ.} 1 word {$az_AZ.} 3 variable {$az_AZ} 1 text az_AZ 0 text . 0 {}}
test parse-12.12 {Tcl_ParseVarName procedure, simple variable name} testparser {
    testparser {$abcdefg} 4
} {- {$abc} 1 word {$abc} 2 variable {$abc} 1 text abc 0 defg}
test parse-12.13 {Tcl_ParseVarName procedure, simple variable name with ::} testparser {
    testparser {$xyz::ab:c} 0
} {- {$xyz::ab:c} 1 word {$xyz::ab:c} 3 variable {$xyz::ab} 1 text xyz::ab 0 text :c 0 {}}
test parse-12.14 {Tcl_ParseVarName procedure, variable names with many colons} testparser {
    testparser {$xyz:::::c} 0
} {- {$xyz:::::c} 1 word {$xyz:::::c} 2 variable {$xyz:::::c} 1 text xyz:::::c 0 {}}
test parse-12.15 {Tcl_ParseVarName procedure, : vs. ::} testparsevarname {
    testparsevarname {$ab:cd} 0 0
} {- {} 0 variable {$ab} 1 text ab 0 :cd}
test parse-12.16 {Tcl_ParseVarName procedure, eof in ::} testparsevarname {
    testparsevarname {$ab::cd} 4 0
} {- {} 0 variable {$ab} 1 text ab 0 ::cd}
test parse-12.17 {Tcl_ParseVarName procedure, eof in ::} testparsevarname {
    testparsevarname {$ab:::cd} 5 0
} {- {} 0 variable {$ab::} 1 text ab:: 0 :cd}
test parse-12.18 {Tcl_ParseVarName procedure, no variable name} testparser {
    testparser {$$ $.} 0
} {- {$$ $.} 2 word {$$} 2 text {$} 0 text {$} 0 word {$.} 2 text {$} 0 text . 0 {}}
test parse-12.19 {Tcl_ParseVarName procedure, EOF before (} testparsevarname {
    testparsevarname {$ab(cd)} 3 0
} {- {} 0 variable {$ab} 1 text ab 0 (cd)}
test parse-12.20 {Tcl_ParseVarName procedure, array reference} testparser {
    testparser {$x(abc)} 0
} {- {$x(abc)} 1 word {$x(abc)} 3 variable {$x(abc)} 2 text x 0 text abc 0 {}}
test parse-12.21 {Tcl_ParseVarName procedure, array reference} testparser {
    testparser {$x(ab$cde[foo bar])} 0
} {- {$x(ab$cde[foo bar])} 1 word {$x(ab$cde[foo bar])} 6 variable {$x(ab$cde[foo bar])} 5 text x 0 text ab 0 variable {$cde} 1 text cde 0 command {[foo bar]} 0 {}}
test parse-12.22 {Tcl_ParseVarName procedure, array reference} testparser {
    testparser {$x([cmd arg]zz)} 0
} {- {$x([cmd arg]zz)} 1 word {$x([cmd arg]zz)} 4 variable {$x([cmd arg]zz)} 3 text x 0 command {[cmd arg]} 0 text zz 0 {}}
test parse-12.23 {Tcl_ParseVarName procedure, missing close paren in array reference} testparser {
    list [catch {testparser {$x(poiu} 0} msg] $msg $errorInfo
} {1 {missing )} {missing )
    (remainder of script: "(poiu")
    invoked from within
"testparser {$x(poiu} 0"}}
test parse-12.24 {Tcl_ParseVarName procedure, missing close paren in array reference} testparsevarname {
    list [catch {testparsevarname {$ab(cd)} 6 0} msg] $msg $errorInfo
} {1 {missing )} {missing )
    (remainder of script: "(cd)")
    invoked from within
"testparsevarname {$ab(cd)} 6 0"}}
test parse-12.25 {Tcl_ParseVarName procedure, nested array reference} testparser {
    testparser {$x(a$y(b$z))} 0
} {- {$x(a$y(b$z))} 1 word {$x(a$y(b$z))} 8 variable {$x(a$y(b$z))} 7 text x 0 text a 0 variable {$y(b$z)} 4 text y 0 text b 0 variable {$z} 1 text z 0 {}}

test parse-13.1 {Tcl_ParseVar procedure} testparsevar {
    set abc 24
    testparsevar {$abc.fg}
} {24 .fg}
test parse-13.2 {Tcl_ParseVar procedure, no variable name} testparsevar {
    testparsevar {$}
} {{$} {}}
test parse-13.3 {Tcl_ParseVar procedure, no variable name} testparsevar {
    testparsevar {$.123}
} {{$} .123}
test parse-13.4 {Tcl_ParseVar procedure, error looking up variable} testparsevar {
    catch {unset abc}
    list [catch {testparsevar {$abc}} msg] $msg
} {1 {can't read "abc": no such variable}}
test parse-13.5 {Tcl_ParseVar procedure, error looking up variable} testparsevar {
    catch {unset abc}
    list [catch {testparsevar {$abc([bogus x y z])}} msg] $msg
} {1 {invalid command name "bogus"}}

test parse-14.1 {Tcl_ParseBraces procedure, computing string length} testparser {
    testparser [bytestring "foo\0 bar"] -1
} {- foo 1 simple foo 1 text foo 0 {}}
test parse-14.2 {Tcl_ParseBraces procedure, computing string length} testparser {
    testparser "foo bar" -1
} {- {foo bar} 2 simple foo 1 text foo 0 simple bar 1 text bar 0 {}}
test parse-14.3 {Tcl_ParseBraces procedure, words in braces} testparser {
    testparser {foo {a $b [concat foo]} {c d}} 0
} {- {foo {a $b [concat foo]} {c d}} 3 simple foo 1 text foo 0 simple {{a $b [concat foo]}} 1 text {a $b [concat foo]} 0 simple {{c d}} 1 text {c d} 0 {}}
test parse-14.4 {Tcl_ParseBraces procedure, empty nested braces} testparser {
    testparser {foo {{}}} 0
} {- {foo {{}}} 2 simple foo 1 text foo 0 simple {{{}}} 1 text {{}} 0 {}}
test parse-14.5 {Tcl_ParseBraces procedure, nested braces} testparser {
    testparser {foo {{a {b} c} {} {d e}}} 0
} {- {foo {{a {b} c} {} {d e}}} 2 simple foo 1 text foo 0 simple {{{a {b} c} {} {d e}}} 1 text {{a {b} c} {} {d e}} 0 {}}
test parse-14.6 {Tcl_ParseBraces procedure, backslashes in words in braces} testparser {
    testparser "foo {a \\n\\\{}" 0
} {- {foo {a \n\{}} 2 simple foo 1 text foo 0 simple {{a \n\{}} 1 text {a \n\{} 0 {}}
test parse-14.7 {Tcl_ParseBraces procedure, missing continuation line in braces} testparser {
    list [catch {testparser "\{abc\\\n" 0} msg] $msg $errorInfo
} {1 {missing close-brace} missing\ close-brace\n\ \ \ \ (remainder\ of\ script:\ \"\{abc\\\n\")\n\ \ \ \ invoked\ from\ within\n\"testparser\ \"\\\{abc\\\\\\n\"\ 0\"}
test parse-14.8 {Tcl_ParseBraces procedure, backslash-newline in braces} testparser {
    testparser "foo {\\\nx}" 0
} {- foo\ \{\\\nx\} 2 simple foo 1 text foo 0 word \{\\\nx\} 2 backslash \\\n 0 text x 0 {}}
test parse-14.9 {Tcl_ParseBraces procedure, backslash-newline in braces} testparser {
    testparser "foo {a \\\n   b}" 0
} {- foo\ \{a\ \\\n\ \ \ b\} 2 simple foo 1 text foo 0 word \{a\ \\\n\ \ \ b\} 3 text {a } 0 backslash \\\n\ \ \  0 text b 0 {}}
test parse-14.10 {Tcl_ParseBraces procedure, backslash-newline in braces} testparser {
    testparser "foo {xyz\\\n }" 0
} {- foo\ \{xyz\\\n\ \} 2 simple foo 1 text foo 0 word \{xyz\\\n\ \} 2 text xyz 0 backslash \\\n\  0 {}}
test parse-14.11 {Tcl_ParseBraces procedure, empty braced string} testparser {
    testparser {foo {}} 0
} {- {foo {}} 2 simple foo 1 text foo 0 simple {{}} 1 text {} 0 {}}
test parse-14.12 {Tcl_ParseBraces procedure, missing close brace} testparser {
    list [catch {testparser "foo \{xy\\\nz" 0} msg] $msg $errorInfo
} {1 {missing close-brace} missing\ close-brace\n\ \ \ \ (remainder\ of\ script:\ \"\{xy\\\nz\")\n\ \ \ \ invoked\ from\ within\n\"testparser\ \"foo\ \\\{xy\\\\\\nz\"\ 0\"}

test parse-15.1 {Tcl_ParseQuotedString procedure, computing string length} testparser {
    testparser [bytestring "foo\0 bar"] -1
} {- foo 1 simple foo 1 text foo 0 {}}
test parse-15.2 {Tcl_ParseQuotedString procedure, computing string length} testparser {
    testparser "foo bar" -1
} {- {foo bar} 2 simple foo 1 text foo 0 simple bar 1 text bar 0 {}}
test parse-15.3 {Tcl_ParseQuotedString procedure, word is quoted string} testparser {
    testparser {foo "a b c" d "efg";} 0
} {- {foo "a b c" d "efg";} 4 simple foo 1 text foo 0 simple {"a b c"} 1 text {a b c} 0 simple d 1 text d 0 simple {"efg"} 1 text efg 0 {}}
test parse-15.4 {Tcl_ParseQuotedString procedure, garbage after quoted string} testparser {
    list [catch {testparser {foo "a b c"d} 0} msg] $msg $errorInfo
} {1 {extra characters after close-quote} {extra characters after close-quote
    (remainder of script: "d")
    invoked from within
"testparser {foo "a b c"d} 0"}}

test parse-15.5 {CommandComplete procedure} {
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
test parse-15.49 {CommandComplete procedure} {
    info complete "abc\\\n "
} 1
test parse-15.50 {CommandComplete procedure} {
    info complete "abc\\\n"
} 0
test parse-15.51 {CommandComplete procedure} "
    info complete \"\\{abc\\}\\{\"
" 1
test parse-15.52 {CommandComplete procedure} {
    info complete "\"abc\"("
} 1
test parse-15.53 {CommandComplete procedure} "
    info complete \" # {\"
" 1
test parse-15.54 {CommandComplete procedure} "
    info complete \"foo bar;# {\"
" 1
test parse-15.55 {CommandComplete procedure} {
    info complete "set x [bytestring \0]; puts hi"
} 1
test parse-15.56 {CommandComplete procedure} {
    info complete "set x [bytestring \0]; \{"
} 0







|





|


|







795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
test parse-15.49 {CommandComplete procedure} {
    info complete "abc\\\n "
} 1
test parse-15.50 {CommandComplete procedure} {
    info complete "abc\\\n"
} 0
test parse-15.51 {CommandComplete procedure} "
    info complete \"\\\{abc\\\}\\\{\"
" 1
test parse-15.52 {CommandComplete procedure} {
    info complete "\"abc\"("
} 1
test parse-15.53 {CommandComplete procedure} "
    info complete \" # \{\"
" 1
test parse-15.54 {CommandComplete procedure} "
    info complete \"foo bar;# \{\"
" 1
test parse-15.55 {CommandComplete procedure} {
    info complete "set x [bytestring \0]; puts hi"
} 1
test parse-15.56 {CommandComplete procedure} {
    info complete "set x [bytestring \0]; \{"
} 0
849
850
851
852
853
854
855
856

857
858
859
} 2
test parse-18.30 {Tcl_SubstObj, side effects} {
    set a 0
    catch {subst {foo[incr a; incr a parse error {}{}]bar}}
    set a
} 1

# cleanup

catch {unset a}
::tcltest::cleanupTests
return







|
>
|
|

940
941
942
943
944
945
946
947
948
949
950
951
} 2
test parse-18.30 {Tcl_SubstObj, side effects} {
    set a 0
    catch {subst {foo[incr a; incr a parse error {}{}]bar}}
    set a
} 1

    cleanupTests
}

namespace delete ::tcl::test::parse
return
Changes to tests/pkg.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
# Commands covered:  pkg
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1995-1996 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.
#
# RCS: @(#) $Id: pkg.test,v 1.9.14.1 2003/06/27 19:10:08 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

# Do all this in a slave interp to avoid garbaging the
# package list
set i [interp create]
interp eval $i [list set argv $argv]
interp eval $i [list package require tcltest]
interp eval $i [list namespace import -force ::tcltest::*]
interp eval $i {

eval package forget [package names]
set oldPkgUnknown [package unknown]
package unknown {}
set oldPath $auto_path
set auto_path ""

test pkg-1.1 {Tcl_PkgProvide procedure} {
    package forget t












|














|







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
# Commands covered:  pkg
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1995-1996 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.
#
# RCS: @(#) $Id: pkg.test,v 1.9.14.2 2004/02/07 05:48:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

# Do all this in a slave interp to avoid garbaging the
# package list
set i [interp create]
interp eval $i [list set argv $argv]
interp eval $i [list package require tcltest]
interp eval $i [list namespace import -force ::tcltest::*]
interp eval $i {

package forget {expand}[package names]
set oldPkgUnknown [package unknown]
package unknown {}
set oldPath $auto_path
set auto_path ""

test pkg-1.1 {Tcl_PkgProvide procedure} {
    package forget t
Changes to tests/pkgMkIndex.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# This file contains tests for the pkg_mkIndex command.
# Note that the tests are limited to Tcl scripts only, there are no shared
# libraries against which to test.
#
# Sourcing this file into Tcl runs the tests and generates output for
# errors.  No output means no errors were found.
#
# Copyright (c) 1998-1999 by Scriptics Corporation.
# All rights reserved.
#
# RCS: @(#) $Id: pkgMkIndex.test,v 1.23.4.1 2003/08/07 21:36:04 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

set fullPkgPath [makeDirectory pkg]










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# This file contains tests for the pkg_mkIndex command.
# Note that the tests are limited to Tcl scripts only, there are no shared
# libraries against which to test.
#
# Sourcing this file into Tcl runs the tests and generates output for
# errors.  No output means no errors were found.
#
# Copyright (c) 1998-1999 by Scriptics Corporation.
# All rights reserved.
#
# RCS: @(#) $Id: pkgMkIndex.test,v 1.23.4.2 2004/02/07 05:48:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

set fullPkgPath [makeDirectory pkg]
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
	    rename package package_original
	    proc package { args } {
		if {[string compare [lindex $args 0] ifneeded] == 0} {
		    set pkg [lindex $args 1]
		    set ver [lindex $args 2]
		    set ::PKGS($pkg:$ver) [lindex $args 3]
		} else {
		    return [eval package_original $args]
		}
	    }
	    array set ::PKGS {}
	}

	set dir [file dirname $filePath]
	$slave eval {set curdir [pwd]}







|







85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
	    rename package package_original
	    proc package { args } {
		if {[string compare [lindex $args 0] ifneeded] == 0} {
		    set pkg [lindex $args 1]
		    set ver [lindex $args 2]
		    set ::PKGS($pkg:$ver) [lindex $args 3]
		} else {
		    return [package_original {expand}$args]
		}
	    }
	    array set ::PKGS {}
	}

	set dir [file dirname $filePath]
	$slave eval {set curdir [pwd]}
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#
# Results:
#  Returns a two element list:
#    0: 1 if the procedure encountered an error, 0 otherwise.
#    1: the error result if element 0 was 1

proc pkgtest::createIndex { args } {
    set parsed [eval parseArgs $args]
    set options [lindex $parsed 0]
    set dirPath [lindex $parsed 1]
    set patternList [lindex $parsed 2]

    file mkdir $dirPath

    if {[catch {
	file delete [file join $dirPath pkgIndex.tcl]
	eval pkg_mkIndex $options [list $dirPath] $patternList
    } err]} {
	return [list 1 $err]
    }

    return [list 0 {}]
}








|








|







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#
# Results:
#  Returns a two element list:
#    0: 1 if the procedure encountered an error, 0 otherwise.
#    1: the error result if element 0 was 1

proc pkgtest::createIndex { args } {
    set parsed [parseArgs {expand}$args]
    set options [lindex $parsed 0]
    set dirPath [lindex $parsed 1]
    set patternList [lindex $parsed 2]

    file mkdir $dirPath

    if {[catch {
	file delete [file join $dirPath pkgIndex.tcl]
	pkg_mkIndex {expand}$options $dirPath {expand}$patternList
    } err]} {
	return [list 1 $err]
    }

    return [list 0 {}]
}

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
#    0: 1 if the procedure encountered an error, 0 otherwise.
#    1: if no error, this is the parsed generated index file, in the format
#	returned by pkgtest::parseIndex.
#	If error, this is the error result.

proc pkgtest::runCreatedIndex {rv args} {
    if {[lindex $rv 0] == 0} {
	set parsed [eval parseArgs $args]
	set dirPath [lindex $parsed 1]
	set idxFile [file join $dirPath pkgIndex.tcl]

	if {[catch {
	    set result [list 0 [makePkgList [parseIndex $idxFile]]]
	} err]} {
	    set result [list 1 $err]
	} 
	file delete $idxFile
    } else {
	set result $rv
    }

    return $result
}
proc pkgtest::runIndex { args } {
    set rv [eval createIndex $args]
    return [eval [list runCreatedIndex $rv] $args]
}

# If there is no match to the patterns, make sure the directory hasn't
# changed on us

test pkgMkIndex-1.1 {nothing matches pattern - current dir is the same} {
    list [pkgtest::runIndex -lazy $fullPkgPath nomatch.tcl] [pwd]







|
















|
|







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
#    0: 1 if the procedure encountered an error, 0 otherwise.
#    1: if no error, this is the parsed generated index file, in the format
#	returned by pkgtest::parseIndex.
#	If error, this is the error result.

proc pkgtest::runCreatedIndex {rv args} {
    if {[lindex $rv 0] == 0} {
	set parsed [parseArgs {expand}$args]
	set dirPath [lindex $parsed 1]
	set idxFile [file join $dirPath pkgIndex.tcl]

	if {[catch {
	    set result [list 0 [makePkgList [parseIndex $idxFile]]]
	} err]} {
	    set result [list 1 $err]
	} 
	file delete $idxFile
    } else {
	set result $rv
    }

    return $result
}
proc pkgtest::runIndex { args } {
    set rv [createIndex {expand}$args]
    return [runCreatedIndex $rv {expand}$args]
}

# If there is no match to the patterns, make sure the directory hasn't
# changed on us

test pkgMkIndex-1.1 {nothing matches pattern - current dir is the same} {
    list [pkgtest::runIndex -lazy $fullPkgPath nomatch.tcl] [pwd]
Changes to tests/proc.test.
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
#
# 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.
#
# RCS: @(#) $Id: proc.test,v 1.11 2002/12/11 21:29:52 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

catch {eval namespace delete [namespace children :: test_ns_*]}
catch {rename p ""}
catch {rename {} ""}
catch {unset msg}

test proc-1.1 {Tcl_ProcObjCmd, put proc in namespace specified in name, if any} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        namespace eval baz {}
    }
    proc test_ns_1::baz::p {} {
        return "p in [namespace current]"
    }
    list [test_ns_1::baz::p] \
         [namespace eval test_ns_1 {baz::p}] \
         [info commands test_ns_1::baz::*]
} {{p in ::test_ns_1::baz} {p in ::test_ns_1::baz} ::test_ns_1::baz::p}
test proc-1.2 {Tcl_ProcObjCmd, namespace specified in proc name must exist} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    list [catch {proc test_ns_1::baz::p {} {}} msg] $msg
} {1 {can't create procedure "test_ns_1::baz::p": unknown namespace}}
test proc-1.3 {Tcl_ProcObjCmd, empty proc name} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    proc :: {} {
        return "empty called"
    }
    list [::] \
         [info body {}]
} {{empty called} {
        return "empty called"
    }}
test proc-1.4 {Tcl_ProcObjCmd, simple proc name and proc defined in namespace} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        namespace eval baz {
            proc p {} {
                return "p in [namespace current]"
            }
        }
    }
    list [test_ns_1::baz::p] \
         [info commands test_ns_1::baz::*]
} {{p in ::test_ns_1::baz} ::test_ns_1::baz::p}
test proc-1.5 {Tcl_ProcObjCmd, qualified proc name and proc defined in namespace} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1::baz {}
    namespace eval test_ns_1 {
        proc baz::p {} {
            return "p in [namespace current]"
        }
    }
    list [test_ns_1::baz::p] \
         [info commands test_ns_1::baz::*] \
         [namespace eval test_ns_1::baz {namespace which p}]
} {{p in ::test_ns_1::baz} ::test_ns_1::baz::p ::test_ns_1::baz::p}
test proc-1.6 {Tcl_ProcObjCmd, namespace code ignores single ":"s in middle or end of command names} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        proc q: {} {return "q:"}
        proc value:at: {} {return "value:at:"}
    }
    list [namespace eval test_ns_1 {q:}] \
         [namespace eval test_ns_1 {value:at:}] \
         [test_ns_1::q:] \







|






|





|











|



|









|











|











|







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
#
# 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.
#
# RCS: @(#) $Id: proc.test,v 1.11.4.1 2004/02/07 05:48:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

catch {namespace delete {expand}[namespace children :: test_ns_*]}
catch {rename p ""}
catch {rename {} ""}
catch {unset msg}

test proc-1.1 {Tcl_ProcObjCmd, put proc in namespace specified in name, if any} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        namespace eval baz {}
    }
    proc test_ns_1::baz::p {} {
        return "p in [namespace current]"
    }
    list [test_ns_1::baz::p] \
         [namespace eval test_ns_1 {baz::p}] \
         [info commands test_ns_1::baz::*]
} {{p in ::test_ns_1::baz} {p in ::test_ns_1::baz} ::test_ns_1::baz::p}
test proc-1.2 {Tcl_ProcObjCmd, namespace specified in proc name must exist} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    list [catch {proc test_ns_1::baz::p {} {}} msg] $msg
} {1 {can't create procedure "test_ns_1::baz::p": unknown namespace}}
test proc-1.3 {Tcl_ProcObjCmd, empty proc name} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    proc :: {} {
        return "empty called"
    }
    list [::] \
         [info body {}]
} {{empty called} {
        return "empty called"
    }}
test proc-1.4 {Tcl_ProcObjCmd, simple proc name and proc defined in namespace} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        namespace eval baz {
            proc p {} {
                return "p in [namespace current]"
            }
        }
    }
    list [test_ns_1::baz::p] \
         [info commands test_ns_1::baz::*]
} {{p in ::test_ns_1::baz} ::test_ns_1::baz::p}
test proc-1.5 {Tcl_ProcObjCmd, qualified proc name and proc defined in namespace} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1::baz {}
    namespace eval test_ns_1 {
        proc baz::p {} {
            return "p in [namespace current]"
        }
    }
    list [test_ns_1::baz::p] \
         [info commands test_ns_1::baz::*] \
         [namespace eval test_ns_1::baz {namespace which p}]
} {{p in ::test_ns_1::baz} ::test_ns_1::baz::p ::test_ns_1::baz::p}
test proc-1.6 {Tcl_ProcObjCmd, namespace code ignores single ":"s in middle or end of command names} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        proc q: {} {return "q:"}
        proc value:at: {} {return "value:at:"}
    }
    list [namespace eval test_ns_1 {q:}] \
         [namespace eval test_ns_1 {value:at:}] \
         [test_ns_1::q:] \
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
test proc-1.8 {Tcl_ProcObjCmd, check that formal parameter names are simple names} {
    catch {rename p ""}
    list [catch {proc p {b:a b::a} { 
    }} msg] $msg
} {1 {procedure "p" has formal parameter "b::a" that is not a simple name}}

test proc-2.1 {TclFindProc, simple proc name and proc not in namespace} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {rename p ""}
    proc p {} {return "p in [namespace current]"}
    info body p
} {return "p in [namespace current]"}
test proc-2.2 {TclFindProc, simple proc name and proc defined in namespace} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        namespace eval baz {
            proc p {} {return "p in [namespace current]"}
        }
    }
    namespace eval test_ns_1::baz {info body p}
} {return "p in [namespace current]"}
test proc-2.3 {TclFindProc, qualified proc name and proc defined in namespace} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1::baz {}
    namespace eval test_ns_1 {
        proc baz::p {} {return "p in [namespace current]"}
    }
    namespace eval test_ns_1 {info body baz::p}
} {return "p in [namespace current]"}
test proc-2.4 {TclFindProc, global proc and executing in namespace} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {rename p ""}
    proc p {} {return "global p"}
    namespace eval test_ns_1::baz {info body p}
} {return "global p"}

test proc-3.1 {TclObjInterpProc, proc defined and executing in same namespace} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    proc p {} {return "p in [namespace current]"}
    p
} {p in ::}
test proc-3.2 {TclObjInterpProc, proc defined and executing in same namespace} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    namespace eval test_ns_1::baz {
        proc p {} {return "p in [namespace current]"}
        p
    }
} {p in ::test_ns_1::baz}
test proc-3.3 {TclObjInterpProc, proc defined and executing in different namespaces} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {rename p ""}
    proc p {} {return "p in [namespace current]"}
    namespace eval test_ns_1::baz {
        p
    }
} {p in ::}
test proc-3.4 {TclObjInterpProc, procs execute in the namespace in which they were defined unless renamed into new namespace} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {rename p ""}
    namespace eval test_ns_1::baz {
        proc p {} {return "p in [namespace current]"}
        rename ::test_ns_1::baz::p ::p
        list [p] [namespace which p]
    }
} {{p in ::} ::p}
test proc-3.5 {TclObjInterpProc, any old result is reset before appending error msg about missing arguments} {
    proc p {x} {info commands 3m}
    list [catch {p} msg] $msg
} {1 {wrong # args: should be "p x"}}

catch {eval namespace delete [namespace children :: test_ns_*]}
catch {rename p ""}
catch {rename {} ""}
catch {unset msg}

if {[catch {package require procbodytest}]} {
    puts "This application couldn't load the \"procbodytest\" package, so I"
    puts "can't test creation of procs whose bodies have type \"procbody\"."







|





|








|







|






|




|






|







|












|







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
test proc-1.8 {Tcl_ProcObjCmd, check that formal parameter names are simple names} {
    catch {rename p ""}
    list [catch {proc p {b:a b::a} { 
    }} msg] $msg
} {1 {procedure "p" has formal parameter "b::a" that is not a simple name}}

test proc-2.1 {TclFindProc, simple proc name and proc not in namespace} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {rename p ""}
    proc p {} {return "p in [namespace current]"}
    info body p
} {return "p in [namespace current]"}
test proc-2.2 {TclFindProc, simple proc name and proc defined in namespace} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        namespace eval baz {
            proc p {} {return "p in [namespace current]"}
        }
    }
    namespace eval test_ns_1::baz {info body p}
} {return "p in [namespace current]"}
test proc-2.3 {TclFindProc, qualified proc name and proc defined in namespace} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1::baz {}
    namespace eval test_ns_1 {
        proc baz::p {} {return "p in [namespace current]"}
    }
    namespace eval test_ns_1 {info body baz::p}
} {return "p in [namespace current]"}
test proc-2.4 {TclFindProc, global proc and executing in namespace} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {rename p ""}
    proc p {} {return "global p"}
    namespace eval test_ns_1::baz {info body p}
} {return "global p"}

test proc-3.1 {TclObjInterpProc, proc defined and executing in same namespace} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    proc p {} {return "p in [namespace current]"}
    p
} {p in ::}
test proc-3.2 {TclObjInterpProc, proc defined and executing in same namespace} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    namespace eval test_ns_1::baz {
        proc p {} {return "p in [namespace current]"}
        p
    }
} {p in ::test_ns_1::baz}
test proc-3.3 {TclObjInterpProc, proc defined and executing in different namespaces} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {rename p ""}
    proc p {} {return "p in [namespace current]"}
    namespace eval test_ns_1::baz {
        p
    }
} {p in ::}
test proc-3.4 {TclObjInterpProc, procs execute in the namespace in which they were defined unless renamed into new namespace} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {rename p ""}
    namespace eval test_ns_1::baz {
        proc p {} {return "p in [namespace current]"}
        rename ::test_ns_1::baz::p ::p
        list [p] [namespace which p]
    }
} {{p in ::} ::p}
test proc-3.5 {TclObjInterpProc, any old result is reset before appending error msg about missing arguments} {
    proc p {x} {info commands 3m}
    list [catch {p} msg] $msg
} {1 {wrong # args: should be "p x"}}

catch {namespace delete {expand}[namespace children :: test_ns_*]}
catch {rename p ""}
catch {rename {} ""}
catch {unset msg}

if {[catch {package require procbodytest}]} {
    puts "This application couldn't load the \"procbodytest\" package, so I"
    puts "can't test creation of procs whose bodies have type \"procbody\"."
Changes to tests/reg.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# reg.test --
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
# (Don't panic if you are seeing this as part of the reg distribution
# and aren't using Tcl -- reg's own regression tester also knows how
# to read this file, ignoring the Tcl-isms.)
#
# Copyright (c) 1998, 1999 Henry Spencer.  All rights reserved.
#
# RCS: @(#) $Id: reg.test,v 1.17.2.1 2003/10/16 02:28:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# All tests require the testregexp command, return if this











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# reg.test --
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
# (Don't panic if you are seeing this as part of the reg distribution
# and aren't using Tcl -- reg's own regression tester also knows how
# to read this file, ignoring the Tcl-isms.)
#
# Copyright (c) 1998, 1999 Henry Spencer.  All rights reserved.
#
# RCS: @(#) $Id: reg.test,v 1.17.2.2 2004/02/07 05:48:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

# All tests require the testregexp command, return if this
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
	}

	# if &, test as both ARE and BRE
	set amp [string first "&" $flags]
	if {$amp >= 0} {
		set f [string range $flags 0 [expr $amp - 1]]
		append f [string range $flags [expr $amp + 1] end]
		eval [linsert $args 0 f [linsert $testid end ARE] ${f} $re \
								$target]
		eval [linsert $args 0 f [linsert $testid end BRE] ${f}b $re \
								$target]
		return
	}

	set f [flags $flags]
	set infoflags [infoflags $flags]
	set ccmd [concat [list testregexp -$ask] $f [list $re]]
	set nsub [expr [llength $args] - 1]







|
<
|
<







227
228
229
230
231
232
233
234

235

236
237
238
239
240
241
242
	}

	# if &, test as both ARE and BRE
	set amp [string first "&" $flags]
	if {$amp >= 0} {
		set f [string range $flags 0 [expr $amp - 1]]
		append f [string range $flags [expr $amp + 1] end]
		f [linsert $testid end ARE] ${f} $re $target {expand}$args

		f [linsert $testid end BRE] ${f}b $re $target {expand}$args

		return
	}

	set f [flags $flags]
	set infoflags [infoflags $flags]
	set ccmd [concat [list testregexp -$ask] $f [list $re]]
	set nsub [expr [llength $args] - 1]
279
280
281
282
283
284
285
286
287


288
289
290
291
292
293
294
295
296
	}

	# if &, test as both BRE and ARE
	set amp [string first "&" $flags]
	if {$amp >= 0} {
		set f [string range $flags 0 [expr $amp - 1]]
		append f [string range $flags [expr $amp + 1] end]
		eval [concat [list matchexpected $opts \
			[linsert $testid end ARE] ${f} $re $target] $args]


		eval [concat [list matchexpected $opts \
			[linsert $testid end BRE] ${f}b $re $target] $args]
		return
	}

	set f [flags $flags]
	set infoflags [infoflags $flags]
	set ccmd [concat [list testregexp -$ask] $f [list $re]]
	set ecmd [concat [list testregexp] $opts $f [list $re $target]]







|
|
>
>
|
|







277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
	}

	# if &, test as both BRE and ARE
	set amp [string first "&" $flags]
	if {$amp >= 0} {
		set f [string range $flags 0 [expr $amp - 1]]
		append f [string range $flags [expr $amp + 1] end]
		matchexpected $opts [linsert $testid end ARE] \
			${f} $re $target {expand}$args


		matchexpected $opts [linsert $testid end BRE] \
			${f}b $re $target {expand}$args
		return
	}

	set f [flags $flags]
	set infoflags [infoflags $flags]
	set ccmd [concat [list testregexp -$ask] $f [list $re]]
	set ecmd [concat [list testregexp] $opts $f [list $re $target]]
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
	set testid [lreplace $testid end end "execute"]
	test $prefix.[tno $testid] [desc $testid] {testregexp} $erun $result
}

# match expected (no missing, empty, or ambiguous submatches)
# m testno flags re target mat submat ...
proc m {args} {
	eval matchexpected [linsert $args 0 [list]]
}

# match expected (full fanciness)
# i testno flags re target mat submat ...
proc i {args} {
	eval matchexpected [linsert $args 0 [list "-indices"]]
}

# partial match expected
# p testno flags re target mat "" ...
# Quirk:  number of ""s must be one more than number of subREs.
proc p {args} {
	set f [lindex $args 1]			;# add ! flag
	set args [lreplace $args 1 1 "!$f"]
	eval matchexpected [linsert $args 0 [list "-indices"]]
}

# test is a knownBug
proc knownBug {args} {
    set ::regBug 1
    uplevel #0 $args
    set ::regBug 0







|





|








|







328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
	set testid [lreplace $testid end end "execute"]
	test $prefix.[tno $testid] [desc $testid] {testregexp} $erun $result
}

# match expected (no missing, empty, or ambiguous submatches)
# m testno flags re target mat submat ...
proc m {args} {
	matchexpected {} {expand}$args
}

# match expected (full fanciness)
# i testno flags re target mat submat ...
proc i {args} {
	matchexpected -indices {expand}$args 
}

# partial match expected
# p testno flags re target mat "" ...
# Quirk:  number of ""s must be one more than number of subREs.
proc p {args} {
	set f [lindex $args 1]			;# add ! flag
	set args [lreplace $args 1 1 "!$f"]
	matchexpected -indices {expand}$args
}

# test is a knownBug
proc knownBug {args} {
    set ::regBug 1
    uplevel #0 $args
    set ::regBug 0
1078
1079
1080
1081
1082
1083
1084
1085















































1086
1087
1088
test reg-32.9 {canmatch functionality -- more complex case} {knownBug} {
    set pat {((\B\B|\Bh+line)[ \t]*|[^\B]%[^\r\n]*)$}
    set line "asd asd"
    # can match at the final d, if '%' follows
    set res [testregexp -xflags -- c $pat $line resvar]
    lappend res $resvar
} {0 6}
















































# cleanup
::tcltest::cleanupTests
return








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



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
test reg-32.9 {canmatch functionality -- more complex case} {knownBug} {
    set pat {((\B\B|\Bh+line)[ \t]*|[^\B]%[^\r\n]*)$}
    set line "asd asd"
    # can match at the final d, if '%' follows
    set res [testregexp -xflags -- c $pat $line resvar]
    lappend res $resvar
} {0 6}

# Tests reg-33.*: Checks for bug fixes

test reg-33.1 {Bug 230589} {
    regexp {[ ]*(^|[^%])%V} "*%V2" m s
} 1

test reg-33.2 {Bug 504785} {
    regexp -inline {([^_.]*)([^.]*)\.(..)(.).*} bbcos_001_c01.q1la
} {bbcos_001_c01.q1la bbcos _001_c01 q1 l}

test reg-33.3 {Bug 505048} {
    regexp {\A\s*[^<]*\s*<([^>]+)>} a<a>
} 1

test reg-33.4 {Bug 505048} {
    regexp {\A\s*([^b]*)b} ab
} 1

test reg-33.5 {Bug 505048} {
    regexp {\A\s*[^b]*(b)} ab
} 1

test reg-33.6 {Bug 505048} {
    regexp {\A(\s*)[^b]*(b)} ab
} 1

test reg-33.7 {Bug 505048} {
    regexp {\A\s*[^b]*b} ab
} 1

test reg-33.8 {Bug 505048} {
    regexp -inline {\A\s*[^b]*b} ab
} ab

test reg-33.9 {Bug 505048} {
    regexp -indices -inline {\A\s*[^b]*b} ab
} {{0 1}}

test reg-33.10 {Bug 840258} {
    regsub {(^|\n)+\.*b} \n.b {} tmp
} 1

test reg-33.11 {Bug 840258} {
    regsub {(^|[\n\r]+)\.*\?<.*?(\n|\r)+} \
	    "TQ\r\n.?<5000267>Test already stopped\r\n" {} tmp
} 1

# cleanup
::tcltest::cleanupTests
return
Changes to tests/resource.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Commands covered:  resource
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1996-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.
#
# RCS: @(#) $Id: resource.test,v 1.7.26.1 2003/10/16 02:28:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

test resource-1.1 {resource tests} {macOnly} {












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Commands covered:  resource
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1996-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.
#
# RCS: @(#) $Id: resource.test,v 1.7.26.2 2004/02/07 05:48:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

test resource-1.1 {resource tests} {macOnly} {
144
145
146
147
148
149
150




151
152
153
154
155
156
157
test resource-5.4 {resource types tests} {macOnly} {
    testWriteTextResource -rsrc fileRsrcName -file rsrc.file  {error "don't source me"}
    set id [resource open rsrc.file]
    set result [resource types $id]
    resource close $id
    set result
} {TEXT}





# resource write tests
test resource-6.1 {resource write tests} {macOnly} {
    list [catch {resource write} msg] $msg
} {1 {wrong # args: should be "resource write ?-id resourceId? ?-name resourceName? ?-file resourceRef? ?-force? resourceType data"}}
test resource-6.2 {resource write tests} {macOnly} {
    list [catch {resource write _bad_type_ data} msg] $msg







>
>
>
>







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
test resource-5.4 {resource types tests} {macOnly} {
    testWriteTextResource -rsrc fileRsrcName -file rsrc.file  {error "don't source me"}
    set id [resource open rsrc.file]
    set result [resource types $id]
    resource close $id
    set result
} {TEXT}
test resource-5.5 {resource types lists} {macOnly} {
    # This should not crash
    catch {foreach f [resource types] { resource list $f }}
} {0}

# resource write tests
test resource-6.1 {resource write tests} {macOnly} {
    list [catch {resource write} msg] $msg
} {1 {wrong # args: should be "resource write ?-id resourceId? ?-name resourceName? ?-file resourceRef? ?-force? resourceType data"}}
test resource-6.2 {resource write tests} {macOnly} {
    list [catch {resource write _bad_type_ data} msg] $msg
Changes to tests/switch.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Commands covered:  switch
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1993 The Regents of the University of California.
# Copyright (c) 1994 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.
#
# RCS: @(#) $Id: switch.test,v 1.9 2003/04/28 10:05:28 dkf Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

test switch-1.1 {simple patterns} {













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Commands covered:  switch
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1993 The Regents of the University of California.
# Copyright (c) 1994 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.
#
# RCS: @(#) $Id: switch.test,v 1.9.2.1 2004/02/07 05:48:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

test switch-1.1 {simple patterns} {
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
	-*	{concat glob}
	-glob	{concat exact}
	default {concat none}
    }
} exact
test switch-3.6 {-exact vs. -glob vs. -regexp} {
    list [catch {switch -foo a b c} msg] $msg
} {1 {bad option "-foo": must be -exact, -glob, -regexp, or --}}

test switch-4.1 {error in executed command} {
    list [catch {switch a a {error "Just a test"} default {format 1}} msg] \
	    $msg $errorInfo
} {1 {Just a test} {Just a test
    while executing
"error "Just a test""







|







85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
	-*	{concat glob}
	-glob	{concat exact}
	default {concat none}
    }
} exact
test switch-3.6 {-exact vs. -glob vs. -regexp} {
    list [catch {switch -foo a b c} msg] $msg
} {1 {bad option "-foo": must be -exact, -glob, -indexvar, -matchvar, -regexp, or --}}

test switch-4.1 {error in executed command} {
    list [catch {switch a a {error "Just a test"} default {format 1}} msg] \
	    $msg $errorInfo
} {1 {Just a test} {Just a test
    while executing
"error "Just a test""
356
357
358
359
360
361
362





























































































363
364
365
rename cswtest2-glob {}
rename iswtest2-glob {}
rename cswtest-exact {}
rename iswtest-exact {}
rename cswtest2-exact {}
rename iswtest2-exact {}






























































































# cleanup
::tcltest::cleanupTests
return







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



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
rename cswtest2-glob {}
rename iswtest2-glob {}
rename cswtest-exact {}
rename iswtest-exact {}
rename cswtest2-exact {}
rename iswtest2-exact {}

# Added due to TIP#75
test switch-11.1 {regexp matching with -matchvar} {
    switch -regexp -matchvar x -- abc {.(.). {set x}}
} {abc b}
test switch-11.2 {regexp matching with -matchvar} {
    set x GOOD
    switch -regexp -matchvar x -- abc {.(.).. {list $x z}}
    set x
} GOOD
test switch-11.3 {regexp matching with -matchvar} {
    switch -regexp -matchvar x -- "a b c" {.(.). {set x}}
} {{a b} { }}
test switch-11.4 {regexp matching with -matchvar} {
    set x BAD
    switch -regexp -matchvar x -- "a b c" {
	bc {list $x YES}
	default {list $x NO}
    }
} {{} NO}
test switch-11.5 {-matchvar without -regexp} {
    set x {}
    list [catch {switch -glob -matchvar x -- abc . {set x}} msg] $x $msg
} {1 {} {-matchvar option requires -regexp option}}
test switch-11.6 {-matchvar unwritable} {
    set x {}
    list [catch {switch -regexp -matchvar x(x) -- abc . {set x}} msg] $x $msg
} {1 {} {can't set "x(x)": variable isn't array}}

test switch-12.1 {regexp matching with -indexvar} {
    switch -regexp -indexvar x -- abc {.(.). {set x}}
} {{0 3} {1 2}}
test switch-12.2 {regexp matching with -indexvar} {
    set x GOOD
    switch -regexp -indexvar x -- abc {.(.).. {list $x z}}
    set x
} GOOD
test switch-12.3 {regexp matching with -indexvar} {
    switch -regexp -indexvar x -- "a b c" {.(.). {set x}}
} {{0 3} {1 2}}
test switch-12.4 {regexp matching with -indexvar} {
    set x BAD
    switch -regexp -indexvar x -- "a b c" {
	bc {list $x YES}
	default {list $x NO}
    }
} {{} NO}
test switch-12.5 {-indexvar without -regexp} {
    set x {}
    list [catch {switch -glob -indexvar x -- abc . {set x}} msg] $x $msg
} {1 {} {-indexvar option requires -regexp option}}
test switch-12.6 {-indexvar unwritable} {
    set x {}
    list [catch {switch -regexp -indexvar x(x) -- abc . {set x}} msg] $x $msg
} {1 {} {can't set "x(x)": variable isn't array}}

test switch-13.1 {-indexvar -matchvar combinations} {
    switch -regexp -indexvar x -matchvar y abc {
	. {list $x $y}
    }
} {{{0 1}} a}
test switch-13.2 {-indexvar -matchvar combinations} {
    switch -regexp -indexvar x -matchvar y abc {
	.$ {list $x $y}
    }
} {{{2 3}} c}
test switch-13.3 {-indexvar -matchvar combinations} {
    switch -regexp -indexvar x -matchvar y abc {
	(.)(.)(.) {list $x $y}
    }
} {{{0 3} {0 1} {1 2} {2 3}} {abc a b c}}
test switch-13.4 {-indexvar -matchvar combinations} {
    set x -
    set y -
    switch -regexp -indexvar x -matchvar y abc {
	(.)(.)(.). -
	default {list $x $y}
    }
} {{} {}}
test switch-13.5 {-indexvar -matchvar combinations} {
    set x -
    set y -
    list [catch {
	switch -regexp -indexvar x(x) -matchvar y abc {. {list $x $y}}
    } msg] $x $y $msg
} {1 - - {can't set "x(x)": variable isn't array}}
test switch-13.6 {-indexvar -matchvar combinations} {
    set x -
    set y -
    list [catch {
	switch -regexp -indexvar x -matchvar y(y) abc {. {list $x $y}}
    } msg] $x $y $msg
} {1 {{0 1}} - {can't set "y(y)": variable isn't array}}

# cleanup
::tcltest::cleanupTests
return
Changes to tests/trace.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Commands covered:  trace
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1991-1993 The Regents of the University of California.
# Copyright (c) 1994 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.
#
# RCS: @(#) $Id: trace.test,v 1.28.2.2 2003/10/16 02:28:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

testConstraint testcmdtrace [llength [info commands testcmdtrace]]













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Commands covered:  trace
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1991-1993 The Regents of the University of California.
# Copyright (c) 1994 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.
#
# RCS: @(#) $Id: trace.test,v 1.28.2.3 2004/02/07 05:48:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

testConstraint testcmdtrace [llength [info commands testcmdtrace]]
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
    $tc eval [list proc foo {} {}]
    $tc eval [list trace add command foo {rename delete} traceCommand]
    interp delete $tc
    set info
} {}

proc traceDelete {cmd old new op} {
    eval trace remove command $cmd [lindex [trace info command $cmd] 0]
    global info
    set info [list $old $new $op]
}
proc traceCmdrename {cmd old new op} {
    rename $old someothername
}
proc traceCmddelete {cmd old new op} {







|







1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
    $tc eval [list proc foo {} {}]
    $tc eval [list trace add command foo {rename delete} traceCommand]
    interp delete $tc
    set info
} {}

proc traceDelete {cmd old new op} {
    trace remove command $cmd {expand}[lindex [trace info command $cmd] 0]
    global info
    set info [list $old $new $op]
}
proc traceCmdrename {cmd old new op} {
    rename $old someothername
}
proc traceCmddelete {cmd old new op} {
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
{expr {$n * [factorial [expr {$n -1 }]]}} 0 6 leavestep
{return 6} enterstep
{return 6} 2 6 leavestep
{if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} 2 6 leavestep
{factorial 3} 0 6 leave}

proc traceDelete {cmd args} {
    eval trace remove execution $cmd [lindex [trace info execution $cmd] 0]
    global info
    set info $args
}

test trace-24.1 {delete trace during enter trace} {
    set info {}
    trace add execution foo enter [list traceDelete foo]







|







1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
{expr {$n * [factorial [expr {$n -1 }]]}} 0 6 leavestep
{return 6} enterstep
{return 6} 2 6 leavestep
{if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] }} 2 6 leavestep
{factorial 3} 0 6 leave}

proc traceDelete {cmd args} {
    trace remove execution $cmd {expand}[lindex [trace info execution $cmd] 0]
    global info
    set info $args
}

test trace-24.1 {delete trace during enter trace} {
    set info {}
    trace add execution foo enter [list traceDelete foo]
Changes to tests/unixInit.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# The file tests the functions in the tclUnixInit.c file.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1997 by 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.
#
# RCS: @(#) $Id: unixInit.test,v 1.30 2002/12/04 07:07:40 hobbs Exp $

package require tcltest 2
namespace import -force ::tcltest::*
catch {unset path}
if {[info exists env(TCL_LIBRARY)]} {
    set oldlibrary $env(TCL_LIBRARY)
    unset env(TCL_LIBRARY)












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# The file tests the functions in the tclUnixInit.c file.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1997 by 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.
#
# RCS: @(#) $Id: unixInit.test,v 1.30.4.1 2004/02/07 05:48:03 dgp Exp $

package require tcltest 2
namespace import -force ::tcltest::*
catch {unset path}
if {[info exists env(TCL_LIBRARY)]} {
    set oldlibrary $env(TCL_LIBRARY)
    unset env(TCL_LIBRARY)
262
263
264
265
266
267
268


































269
270
271
272
273
274
275
    set x [lrange [getlibpath /tmp/sparkly/tcltest] 0 4]

    file delete -force /tmp/sparkly
    file delete -force /tmp/library
    set x
} [list /tmp/lib/tcl[info tclversion] /lib/tcl[info tclversion] \
        /tmp/library /library /tcl[info patchlevel]/library]


































test unixInit-3.1 {TclpSetInitialEncodings} -constraints {
	unixOnly stdio
} -body {
    set env(LANG) C

    set f [open "|[list [interpreter]]" w+]
    fconfigure $f -buffering none







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







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
    set x [lrange [getlibpath /tmp/sparkly/tcltest] 0 4]

    file delete -force /tmp/sparkly
    file delete -force /tmp/library
    set x
} [list /tmp/lib/tcl[info tclversion] /lib/tcl[info tclversion] \
        /tmp/library /library /tcl[info patchlevel]/library]

test unixInit-2.10 {TclpInitLibraryPath: executable relative} -constraints {
	unixOnly stdio
} -setup {
    set tmpDir [makeDirectory tmp]
    set sparklyDir [makeDirectory sparkly $tmpDir]
    set execPath [file join [makeDirectory bin $sparklyDir] tcltest]
    file copy [interpreter] $execPath
    set libDir [makeDirectory lib $sparklyDir]
    set scriptDir [makeDirectory tcl[info tclversion] $libDir]
    makeFile {} init.tcl $scriptDir
    set saveDir [pwd]
    cd $libDir
} -body {
    # Checking for Bug 832657
    lrange [getlibpath [file join .. bin tcltest]] 2 3
} -cleanup {
    cd $saveDir
    unset saveDir
    removeFile init.tcl $scriptDir
    unset scriptDir
    removeDirectory tcl[info tclversion] $libDir
    unset libDir
    file delete $execPath
    unset execPath
    removeDirectory bin $sparklyDir
    removeDirectory lib $sparklyDir
    unset sparklyDir
    removeDirectory sparkly $tmpDir
    unset tmpDir
    removeDirectory tmp
} -result [list [file join [temporaryDirectory] tmp sparkly library] \
	[file join [temporaryDirectory] tmp library] ]

test unixInit-3.1 {TclpSetInitialEncodings} -constraints {
	unixOnly stdio
} -body {
    set env(LANG) C

    set f [open "|[list [interpreter]]" w+]
    fconfigure $f -buffering none
Changes to tests/upvar.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Commands covered:  upvar
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1991-1993 The Regents of the University of California.
# Copyright (c) 1994 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.
#
# RCS: @(#) $Id: upvar.test,v 1.7 2000/04/10 17:19:05 ericm Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

test upvar-1.1 {reading variables with upvar} {













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Commands covered:  upvar
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1991-1993 The Regents of the University of California.
# Copyright (c) 1994 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.
#
# RCS: @(#) $Id: upvar.test,v 1.7.26.1 2004/02/07 05:48:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

test upvar-1.1 {reading variables with upvar} {
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
} {1 {variable "a" has traces: can't use for upvar}}
test upvar-8.8 {create nested array with upvar} {
    proc p1 {} {upvar x(a) b; set b(2) 44}
    catch {unset x}
    list [catch p1 msg] $msg
} {1 {can't set "b(2)": variable isn't array}}
test upvar-8.9 {upvar won't create namespace variable that refers to procedure variable} {
    catch {eval namespace delete [namespace children :: test_ns_*]}
    catch {rename MakeLink ""}
    namespace eval ::test_ns_1 {}
    proc MakeLink {a} {
        namespace eval ::test_ns_1 {
	    upvar a a
        }
        unset ::test_ns_1::a







|







316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
} {1 {variable "a" has traces: can't use for upvar}}
test upvar-8.8 {create nested array with upvar} {
    proc p1 {} {upvar x(a) b; set b(2) 44}
    catch {unset x}
    list [catch p1 msg] $msg
} {1 {can't set "b(2)": variable isn't array}}
test upvar-8.9 {upvar won't create namespace variable that refers to procedure variable} {
    catch {namespace delete {expand}[namespace children :: test_ns_*]}
    catch {rename MakeLink ""}
    namespace eval ::test_ns_1 {}
    proc MakeLink {a} {
        namespace eval ::test_ns_1 {
	    upvar a a
        }
        unset ::test_ns_1::a
Changes to tests/winConsole.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# This file tests the tclWinConsole.c file.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 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.
#
# RCS: @(#) $Id: winConsole.test,v 1.5 2000/04/10 17:19:06 ericm Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# This file tests the tclWinConsole.c file.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 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.
#
# RCS: @(#) $Id: winConsole.test,v 1.5.26.1 2004/02/07 05:48:03 dgp Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
    fconfigure stdin -blocking 0 -buffering line

    set result {}
    vwait result

    #cleanup the fileevent
    fileevent stdin readable {}
    eval fconfigure stdin $oldmode

    set result

}  "abcdef"

#cleanup

::tcltest::cleanupTests
return








|










35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
    fconfigure stdin -blocking 0 -buffering line

    set result {}
    vwait result

    #cleanup the fileevent
    fileevent stdin readable {}
    fconfigure stdin {expand}$oldmode

    set result

}  "abcdef"

#cleanup

::tcltest::cleanupTests
return

Changes to tests/winFCmd.test.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# This file tests the tclWinFCmd.c file.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1996-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.
#
# RCS: @(#) $Id: winFCmd.test,v 1.20.4.2 2003/10/16 02:28:03 dgp Exp $
#

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# This file tests the tclWinFCmd.c file.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1996-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.
#
# RCS: @(#) $Id: winFCmd.test,v 1.20.4.3 2004/02/07 05:48:03 dgp Exp $
#

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
proc cleanup {args} {
    foreach p ". $args" {
	set x ""
	catch {
	    set x [glob -directory $p tf* td*]
	}
	if {$x != ""} {
	    catch {eval file delete -force -- $x}
	}
    }
}

if {[string equal $tcl_platform(platform) "windows"]} {
    if {[string equal $tcl_platform(os) "Windows NT"] \
      && [string equal [string index $tcl_platform(osVersion) 0] "5"]} {







|







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
proc cleanup {args} {
    foreach p ". $args" {
	set x ""
	catch {
	    set x [glob -directory $p tf* td*]
	}
	if {$x != ""} {
	    catch {file delete -force -- {expand}$x}
	}
    }
}

if {[string equal $tcl_platform(platform) "windows"]} {
    if {[string equal $tcl_platform(os) "Windows NT"] \
      && [string equal [string index $tcl_platform(osVersion) 0] "5"]} {
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
} {1 {nul EACCES}}
test winFCmd-6.11 {TclpRemoveDirectory: attr == -1} {pcOnly nt} {
    cleanup
    set res [list [catch {testfile rmdir /} msg] $msg]
    # WinXP returns EEXIST, WinNT seems to return EACCES.  No policy
    # decision has been made as to which is correct.
    regsub {E(ACCES|EXIST)} $res "EACCES or EEXIST"
} {1 {C:/ EACCES or EEXIST}}
test winFCmd-6.12 {TclpRemoveDirectory: errno == EACCES} {pcOnly 95} {
    cleanup
    createfile tf1
    set res [catch {testfile rmdir tf1} msg]
    # get rid of path
    set msg [list [file tail [lindex $msg 0]] [lindex $msg 1]]
    list $res $msg







|







606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
} {1 {nul EACCES}}
test winFCmd-6.11 {TclpRemoveDirectory: attr == -1} {pcOnly nt} {
    cleanup
    set res [list [catch {testfile rmdir /} msg] $msg]
    # WinXP returns EEXIST, WinNT seems to return EACCES.  No policy
    # decision has been made as to which is correct.
    regsub {E(ACCES|EXIST)} $res "EACCES or EEXIST"
} [list 1 [list / EACCES or EEXIST]]
test winFCmd-6.12 {TclpRemoveDirectory: errno == EACCES} {pcOnly 95} {
    cleanup
    createfile tf1
    set res [catch {testfile rmdir tf1} msg]
    # get rid of path
    set msg [list [file tail [lindex $msg 0]] [lindex $msg 1]]
    list $res $msg
1012
1013
1014
1015
1016
1017
1018
1019
1020

1021








1022
1023

1024
1025
1026
1027
1028
1029
1030
1031
} "${d}:/bar"
test winFCmd-16.8 {Windows file normalization} {pcOnly} {
    file norm ///bar
} "${d}:/bar"
test winFCmd-16.9 {Windows file normalization} {pcOnly} {
    file norm /bar/foo
} "${d}:/bar/foo"
test winFCmd-16.10 {Windows file normalization} {pcOnly knownBug} {
    if {$d eq "C"} { set dd "D" } else { set dd "C" }

    file norm ${dd}:foo








} {Tcl doesn't know about a drive-specific cwd}


unset d pwd

# This block of code used to occur after the "return" call, so I'm
# commenting it out and assuming that this code is still under construction.
#foreach source {tef ted tnf tnd "" nul com1} {
#    foreach chmodsrc {000 755} {
#        foreach dest "tfn tfe tdn tdempty tdfull td1/td2 $p $p/td1 {} nul" {
#	    foreach chmoddst {000 755} {







<
|
>

>
>
>
>
>
>
>
>
|

>
|







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
} "${d}:/bar"
test winFCmd-16.8 {Windows file normalization} {pcOnly} {
    file norm ///bar
} "${d}:/bar"
test winFCmd-16.9 {Windows file normalization} {pcOnly} {
    file norm /bar/foo
} "${d}:/bar/foo"

if {$d eq "C"} { set dd "D" } else { set dd "C" }
test winFCmd-16.10 {Windows file normalization} {pcOnly} {
    file norm ${dd}:foo
} "${dd}:/foo"
test winFCmd-16.11 {Windows file normalization} {pcOnly cdrom} {
    cd ${d}:
    cd $cdrom
    cd ${d}:
    cd $cdrom
    # Must not crash
    set result "no crash"
} {no crash}

cd $pwd
unset d dd pwd

# This block of code used to occur after the "return" call, so I'm
# commenting it out and assuming that this code is still under construction.
#foreach source {tef ted tnf tnd "" nul com1} {
#    foreach chmodsrc {000 755} {
#        foreach dest "tfn tfe tdn tdempty tdfull td1/td2 $p $p/td1 {} nul" {
#	    foreach chmoddst {000 755} {
Changes to tests/winFile.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 tests the tclWinFile.c file.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  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.
#
# RCS: @(#) $Id: winFile.test,v 1.10 2003/04/11 16:00:05 vincentdarley Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest



    namespace import -force ::tcltest::*









}

test winFile-1.1 {TclpGetUserHome} {pcOnly} {
    list [catch {glob ~nosuchuser} msg] $msg
} {1 {user "nosuchuser" doesn't exist}}
test winFile-1.2 {TclpGetUserHome} {pcOnly nt nonPortable} {
    # The administrator account should always exist.












|

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







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
# This file tests the tclWinFile.c file.
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  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.
#
# RCS: @(#) $Id: winFile.test,v 1.10.2.1 2004/02/07 05:48:03 dgp Exp $


if {[catch {package require tcltest 2.0.2}]} {
    puts stderr "Skipping tests in [info script]. tcltest 2.0.2 required."
    return
}
namespace import -force ::tcltest::*

if {[info commands ::testvolumetype] == ""} {
    tcltest::testConstraint notNTFS 0
} else {
    if {![string equal "NTFS" [testvolumetype]]} {
	tcltest::testConstraint notNTFS 0
    } else {
	tcltest::testConstraint notNTFS 1
    }
}

test winFile-1.1 {TclpGetUserHome} {pcOnly} {
    list [catch {glob ~nosuchuser} msg] $msg
} {1 {user "nosuchuser" doesn't exist}}
test winFile-1.2 {TclpGetUserHome} {pcOnly nt nonPortable} {
    # The administrator account should always exist.
73
74
75
76
77
78
79











































































































































80
81
82
83
84
85
86
		  and [testvolumetype $vol] are different"
		break
	    }
	}
    }
    set res
} {volume types ok}












































































































































# cleanup
::tcltest::cleanupTests
return










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







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
		  and [testvolumetype $vol] are different"
		break
	    }
	}
    }
    set res
} {volume types ok}

proc cacls {fname args} {
    string trim [eval [list exec cacls [file nativename $fname]] $args <<y]
}

# dir/q output:
# 2003-11-03  20:36                  598 OCTAVIAN\benny         filename.txt
proc getuser {fname} {
    set tryname $fname
    if {[file isdirectory $fname]} {
	set tryname [file dirname $fname]
    }
    set tail [file tail $tryname]
    set dirtext [exec cmd /c dir /q [file nativename $fname]]
    set owner ""
    foreach line [split $dirtext "\n"] {
	if {[string match -nocase "* $tail" $line]} {
	    set attrs [string range $line \
	      0 end-[string length $tail]]
	    regexp { [A-Z]+\\.*$} $attrs owner
	    set owner [string trim $owner]
	}
    }
    if {"" == "$owner"} {
	error "getuser: Owner not found in output of dir/q"
    }
    return $owner
}

proc test_read {fname} {
    if {[catch {set ifs [open $fname r]}]} {
	return 0
    }
    set readfailed [catch {read $ifs}]
    return [expr {![catch {close $ifs}] && !$readfailed}]
}

proc test_writ {fname} {
    if {[catch {set ofs [open $fname w]}]} {
	return 0
    }
    set writefailed [catch {puts $ofs "Hello"}]
    return [expr {![catch {close $ofs}] && !$writefailed}]
}

proc test_access {fname read writ} {
    set problem {}
    foreach type {read writ} {
	if {[set $type] != [file ${type}able $fname]} {
	    lappend problem "[set $type] != \[file ${type}able $fname\]"
	}
	if {[set $type] != [test_${type} $fname]} {
	    lappend problem "[set $type] != \[test_${type} $fname\]"
	}
    }
    if {[llength $problem]} {
	return "Problem [join $problem \n]\nActual rights are: [cacls $fname]"
    } else {
	return ""
    }
}

# Create the test file
# NOTE: [tcltest::makeFile] not used.  Presumably to force file
# creation in a particular filesystem?  If not, try [makeFile]
# in a -setup script.
set fname test.dat
file delete $fname
close [open $fname w]

test winFile-4.0 {
    Enhanced NTFS user/group permissions: test no acccess
} -constraints {
    notNTFS pcOnly nt
} -setup {
    set owner [getuser $fname]
    set user $::env(USERDOMAIN)\\$::env(USERNAME)
} -body {
    # Clean out all well-known ACLs
    catch {cacls $fname /E /R "Everyone"} result
    catch {cacls $fname /E /R $user} result
    catch {cacls $fname /E /R $owner} result
    cacls $fname /E /P $user:N
    test_access $fname 0 0
} -result {}

test winFile-4.1 {
    Enhanced NTFS user/group permissions: test readable only
} -constraints {
    notNTFS pcOnly nt
} -setup {
    set user $::env(USERDOMAIN)\\$::env(USERNAME)
} -body {
    cacls $fname /E /P $user:N
    cacls $fname /E /G $user:R
    test_access $fname 1 0
} -result {}

test winFile-4.2 {
    Enhanced NTFS user/group permissions: test writable only
} -constraints {
    notNTFS pcOnly nt
} -setup {
    set user $::env(USERDOMAIN)\\$::env(USERNAME)
} -body {
    catch {cacls $fname /E /R $user} result
    cacls $fname /E /P $user:N
    cacls $fname /E /G $user:W
    test_access $fname 0 1
} -result {}

test winFile-4.3 {
    Enhanced NTFS user/group permissions: test read+write
} -constraints {
    notNTFS pcOnly nt
} -setup {
    set user $::env(USERDOMAIN)\\$::env(USERNAME)
} -body {
    catch {cacls $fname /E /R $user} result
    cacls $fname /E /P $user:N
    cacls $fname /E /G $user:R
    cacls $fname /E /G $user:W
    test_access $fname 1 1
} -result {}

test winFile-4.4 {
    Enhanced NTFS user/group permissions: test full access
} -constraints {
    notNTFS pcOnly nt
} -setup {
    set user $::env(USERDOMAIN)\\$::env(USERNAME)
} -body {
    catch {cacls $fname /E /R $user} result
    cacls $fname /E /P $user:N
    cacls $fname /E /G $user:F
    test_access $fname 1 1
} -result {}

file delete $fname

# cleanup
::tcltest::cleanupTests
return



Changes to tests/winPipe.test.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#
# Copyright (c) 1996 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.
#
# RCS: @(#) $Id: winPipe.test,v 1.22 2002/12/17 02:47:39 davygrvy Exp $

package require tcltest
namespace import -force ::tcltest::*

testConstraint exec [llength [info commands exec]]

set bindir [file join [pwd] [file dirname [info nameofexecutable]]]







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#
# Copyright (c) 1996 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.
#
# RCS: @(#) $Id: winPipe.test,v 1.22.4.1 2004/02/07 05:48:03 dgp Exp $

package require tcltest
namespace import -force ::tcltest::*

testConstraint exec [llength [info commands exec]]

set bindir [file join [pwd] [file dirname [info nameofexecutable]]]
311
312
313
314
315
316
317



318

























































319
320
321
322
323





















































324
325
326
327
328
329
330
    lappend x [catch {close $f} msg] $msg
} {writable timeout 0 {}}

set path(echoArgs.tcl) [makeFile {
    puts "[list $argv0 $argv]"
} echoArgs.tcl]




test winpipe-7.1 {BuildCommandLine: null arguments} {pcOnly exec} {

























































    exec [interpreter] $path(echoArgs.tcl) foo "" bar
} [list $path(echoArgs.tcl) {foo {} bar}]
test winpipe-7.2 {BuildCommandLine: null arguments} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo \" bar
} [list $path(echoArgs.tcl) {foo {"} bar}]






















































# restore old values for env(TMP) and env(TEMP)

if {[catch {set env(TMP) $env_tmp}]} {
    unset env(TMP)
}
if {[catch {set env(TEMP) $env_temp}]} {







>
>
>

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

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







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
    lappend x [catch {close $f} msg] $msg
} {writable timeout 0 {}}

set path(echoArgs.tcl) [makeFile {
    puts "[list $argv0 $argv]"
} echoArgs.tcl]


### validate the raw output of BuildCommandLine().
###
test winpipe-7.1 {BuildCommandLine: null arguments} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo "" bar
} {foo "" bar}
test winpipe-7.2 {BuildCommandLine: null arguments} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo {} bar
} {foo "" bar}
test winpipe-7.3 {BuildCommandLine: dbl quote quoting #1} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo {"} bar
} {foo \" bar}
test winpipe-7.4 {BuildCommandLine: dbl quote quoting #2} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo {""} bar
} {foo \"\" bar}
test winpipe-7.5 {BuildCommandLine: dbl quote quoting #3} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo {" } bar
} {foo "\" " bar}
test winpipe-7.6 {BuildCommandLine: dbl quote quoting #4} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo {a="b"} bar
} {foo a=\"b\" bar}
test winpipe-7.7 {BuildCommandLine: dbl quote quoting #5} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo {a = "b"} bar
} {foo "a = \"b\"" bar}
test winpipe-7.8 {BuildCommandLine: dbl quote quoting #6} {pcOnly exec} {
    exec $env(COMSPEC) /c echo {"hello"} {""hello""} {"""hello"""} {"\"hello\""} {he llo} {he " llo}
} {\"hello\" \"\"hello\"\" \"\"\"hello\"\"\" \"\\\"hello\\\"\" "he llo" "he \" llo"}
test winpipe-7.9 {BuildCommandLine: N backslashes followed a quote rule #1} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo \\ bar
} {foo \ bar}
test winpipe-7.10 {BuildCommandLine: N backslashes followed a quote rule #2} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo \\\\ bar
} {foo \\ bar}
test winpipe-7.11 {BuildCommandLine: N backslashes followed a quote rule #3} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo \\\ \\ bar
} {foo "\ \\" bar}
test winpipe-7.12 {BuildCommandLine: N backslashes followed a quote rule #4} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo \\\ \\\\ bar
} {foo "\ \\\\" bar}
test winpipe-7.13 {BuildCommandLine: N backslashes followed a quote rule #5} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo \\\ \\\\\\ bar
} {foo "\ \\\\\\" bar}
test winpipe-7.14 {BuildCommandLine: N backslashes followed a quote rule #6} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo \\\ \\\" bar
} {foo "\ \\\"" bar}
test winpipe-7.15 {BuildCommandLine: N backslashes followed a quote rule #7} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo \\\ \\\\\" bar
} {foo "\ \\\\\"" bar}
test winpipe-7.16 {BuildCommandLine: N backslashes followed a quote rule #8} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo \\\ \\\\\\\" bar
} {foo "\ \\\\\\\"" bar}
test winpipe-7.17 {BuildCommandLine: special chars #4} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo \{ bar
} "foo \{ bar"
test winpipe-7.18 {BuildCommandLine: special chars #5} {pcOnly exec} {
    exec $env(COMSPEC) /c echo foo \} bar
} "foo \} bar"

### validate the pass-thru from BuildCommandLine() to the crt's parse_cmdline().
###
test winpipe-8.1 {BuildCommandLine/parse_cmdline pass-thru: null arguments} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo "" bar
} [list $path(echoArgs.tcl) [list foo {} bar]]
test winpipe-8.2 {BuildCommandLine/parse_cmdline pass-thru: null arguments} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo {} bar
} [list $path(echoArgs.tcl) [list foo {} bar]]
test winpipe-8.3 {BuildCommandLine/parse_cmdline pass-thru: dbl quote quoting #1} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo {"} bar
} [list $path(echoArgs.tcl) [list foo {"} bar]]
test winpipe-8.4 {BuildCommandLine/parse_cmdline pass-thru: dbl quote quoting #2} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo {""} bar
} [list $path(echoArgs.tcl) [list foo {""} bar]]
test winpipe-8.5 {BuildCommandLine/parse_cmdline pass-thru: dbl quote quoting #3} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo {" } bar
} [list $path(echoArgs.tcl) [list foo {" } bar]]
test winpipe-8.6 {BuildCommandLine/parse_cmdline pass-thru: dbl quote quoting #4} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo {a="b"} bar
} [list $path(echoArgs.tcl) [list foo {a="b"} bar]]
test winpipe-8.7 {BuildCommandLine/parse_cmdline pass-thru: dbl quote quoting #5} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo {a = "b"} bar
} [list $path(echoArgs.tcl) [list foo {a = "b"} bar]]
test winpipe-8.8 {BuildCommandLine/parse_cmdline pass-thru: dbl quote quoting #6} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) {"hello"} {""hello""} {"""hello"""} {"\"hello\""} {he llo} {he " llo}
} [list $path(echoArgs.tcl) [list {"hello"} {""hello""} {"""hello"""} {"\"hello\""} {he llo} {he " llo}]]
test winpipe-8.9 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #1} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo \\ bar
} [list $path(echoArgs.tcl) [list foo \\ bar]]
test winpipe-8.10 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #2} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo \\\\ bar
} [list $path(echoArgs.tcl) [list foo \\\\ bar]]
test winpipe-8.11 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #3} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo \\\ \\ bar
} [list $path(echoArgs.tcl) [list foo \\\ \\ bar]]
test winpipe-8.12 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #4} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo \\\ \\\\ bar
} [list $path(echoArgs.tcl) [list foo \\\ \\\\ bar]]
test winpipe-8.13 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #5} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo \\\ \\\\\\ bar
} [list $path(echoArgs.tcl) [list foo \\\ \\\\\\ bar]]
test winpipe-8.14 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #6} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo \\\ \\\" bar
} [list $path(echoArgs.tcl) [list foo \\\ \\\" bar]]
test winpipe-8.15 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #7} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo \\\ \\\\\" bar
} [list $path(echoArgs.tcl) [list foo \\\ \\\\\" bar]]
test winpipe-8.16 {BuildCommandLine/parse_cmdline pass-thru: N backslashes followed a quote rule #8} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo \\\ \\\\\\\" bar
} [list $path(echoArgs.tcl) [list foo \\\ \\\\\\\" bar]]
test winpipe-8.17 {BuildCommandLine/parse_cmdline pass-thru: special chars #1} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo \{ bar
} [list $path(echoArgs.tcl) [list foo \{ bar]]
test winpipe-8.18 {BuildCommandLine/parse_cmdline pass-thru: special chars #2} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo \} bar
} [list $path(echoArgs.tcl) [list foo \} bar]]
test winpipe-8.19 {ensure parse_cmdline isn't doing wildcard replacement} {pcOnly exec} {
    exec [interpreter] $path(echoArgs.tcl) foo * makefile.?c bar
} [list $path(echoArgs.tcl) [list foo * makefile.?c bar]]



# restore old values for env(TMP) and env(TEMP)

if {[catch {set env(TMP) $env_tmp}]} {
    unset env(TMP)
}
if {[catch {set env(TEMP) $env_temp}]} {
Changes to tools/man2tcl.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
40
41
42
 *	man2tcl ?fileName?
 *
 * Copyright (c) 1995 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: man2tcl.c,v 1.7 2002/05/08 23:48:13 davygrvy Exp $
 */

static char sccsid[] = "@(#) man2tcl.c 1.3 95/08/12 17:34:08";

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#ifndef NO_ERRNO_H
#include <errno.h>
#endif

/*
 * Imported things that aren't defined in header files:
 */







extern int errno;


/*
 * Current line number, used for error messages.
 */

static int lineNumber;








|















>
>
>
>
>
>

>







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
 *	man2tcl ?fileName?
 *
 * Copyright (c) 1995 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: man2tcl.c,v 1.7.4.1 2004/02/07 05:48:03 dgp Exp $
 */

static char sccsid[] = "@(#) man2tcl.c 1.3 95/08/12 17:34:08";

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#ifndef NO_ERRNO_H
#include <errno.h>
#endif

/*
 * Imported things that aren't defined in header files:
 */

/*
 * Some <errno.h> define errno to be something complex and
 * thread-aware; in that case we definitely do not want to declare
 * errno ourselves!
 */
#ifndef errno
extern int errno;
#endif

/*
 * Current line number, used for error messages.
 */

static int lineNumber;

Changes to tools/tcl.wse.in.
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
item: If/While Statement
  Variable=COMPONENTS
  Value=A
  Flags=00001010
end
item: Install File
  Source=${__TCLBASEDIR__}\library\msgcat\pkgIndex.tcl
  Destination=%MAINDIR%\lib\tcl%VER%\msgcat1.2\pkgIndex.tcl
  Flags=0000000010000010
end
item: Install File
  Source=${__TCLBASEDIR__}\library\msgcat\msgcat.tcl
  Destination=%MAINDIR%\lib\tcl%VER%\msgcat1.2\msgcat.tcl
  Flags=0000000010000010
end
item: Install File
  Source=${__TCLBASEDIR__}\library\tcltest\pkgIndex.tcl
  Destination=%MAINDIR%\lib\tcl%VER%\tcltest2.0\pkgIndex.tcl
  Flags=0000000000000010
end







|




|







1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
item: If/While Statement
  Variable=COMPONENTS
  Value=A
  Flags=00001010
end
item: Install File
  Source=${__TCLBASEDIR__}\library\msgcat\pkgIndex.tcl
  Destination=%MAINDIR%\lib\tcl%VER%\msgcat1.4\pkgIndex.tcl
  Flags=0000000010000010
end
item: Install File
  Source=${__TCLBASEDIR__}\library\msgcat\msgcat.tcl
  Destination=%MAINDIR%\lib\tcl%VER%\msgcat1.4\msgcat.tcl
  Flags=0000000010000010
end
item: Install File
  Source=${__TCLBASEDIR__}\library\tcltest\pkgIndex.tcl
  Destination=%MAINDIR%\lib\tcl%VER%\tcltest2.0\pkgIndex.tcl
  Flags=0000000000000010
end
Changes to tools/tcltk-man2html.tcl.
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
	    man-puts <P>$rest
	    return
	}
	if {[next-op-is .RE rest]} {
	    return
	}
    }
    man-puts <DL><P><DD>
    while {[more-text]} {
	set line [next-text]
	if {[is-a-directive $line]} {
	    split-directive $line code rest
	    switch -exact $code {
		.RE {
		    break







|







475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
	    man-puts <P>$rest
	    return
	}
	if {[next-op-is .RE rest]} {
	    return
	}
    }
    man-puts <DL><DD>
    while {[more-text]} {
	set line [next-text]
	if {[is-a-directive $line]} {
	    split-directive $line code rest
	    switch -exact $code {
		.RE {
		    break
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
## 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]} {
	# blank label, plain indent, no contents entry
	man-puts <DL><P><DD>
	while {[more-text]} {
	    set line [next-text]
	    if {[is-a-directive $line]} {
		split-directive $line code rest
		if {[string equal $code ".IP"] && [string equal $rest {}]} {
		    man-puts "<P>"
		    continue







|







508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
## 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]} {
	# blank label, plain indent, no contents entry
	man-puts <DL><DD>
	while {[more-text]} {
	    set line [next-text]
	    if {[is-a-directive $line]} {
		split-directive $line code rest
		if {[string equal $code ".IP"] && [string equal $rest {}]} {
		    man-puts "<P>"
		    continue
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
	if {[string compare $context ".SH"]} {
	    man-puts <P>
	}
	man-puts <DL>
	lappend manual(section-toc) <DL>
	backup-text 1
	set accept_RE 0

	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 {[string equal $manual(section) "ARGUMENTS"] || \
				[regexp {^\[\d+\]$} $rest]} {
			    man-puts "<P><DT>$rest<DD>"
			} else {
			    man-puts "<P><DT>[long-toc $rest]<DD>"
			}
			if {[string equal $manual(name):$manual(section) \
				"selection:DESCRIPTION"]} {
			    if {[match-text .RE @rest .RS .RS]} {
				man-puts <DT>[long-toc $rest]<DD>
			    }
			}







>












|

|







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
	if {[string compare $context ".SH"]} {
	    man-puts <P>
	}
	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 {[string equal $manual(section) "ARGUMENTS"] || \
				[regexp {^\[\d+\]$} $rest]} {
			    man-puts "$para<DT>$rest<DD>"
			} else {
			    man-puts "$para<DT>[long-toc $rest]<DD>"
			}
			if {[string equal $manual(name):$manual(section) \
				"selection:DESCRIPTION"]} {
			    if {[match-text .RE @rest .RS .RS]} {
				man-puts <DT>[long-toc $rest]<DD>
			    }
			}
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600

601
602
603
604
605
606
607
			} else {
			    output-directive $line
			}
		    }
		    .PP {
			if {[match-text @rest1 .br @rest2 .RS]} {
			    # yet another nroff kludge as above
			    man-puts "<P><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

				break
			    } else {
				man-puts "<P>$rest"
				incr accept_RE -1
			    }
			} elseif {$accept_RE} {
			    output-directive $line







|







>







587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
			} else {
			    output-directive $line
			}
		    }
		    .PP {
			if {[match-text @rest1 .br @rest2 .RS]} {
			    # 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
621
622
623
624
625
626
627

628
629
630
631
632
633
634
635
636
			backup-text 1
			break
		    }
		}
	    } else {
		man-puts $line
	    }

	}
	man-puts <P></DL>
	lappend manual(section-toc) </DL>
	if {$accept_RE} {
	    manerror "missing .RE in output-IP-list"
	}
    }
}
##







>

|







623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
			backup-text 1
			break
		    }
		}
	    } 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"
	}
    }
}
##
1398
1399
1400
1401
1402
1403
1404
1405


1406
1407
1408
1409
1410
1411
1412
			    lappend manual(text) [concat .IP [process-text "[lindex $rest 0] \\fB[lindex $rest 1]\\fR ([lindex $rest 2])"]]
			}
			.IP {
			    regexp {^(.*) +\d+$} $rest all rest
			    lappend manual(text) ".IP [process-text [unquote [string trim $rest]]]"
			}
			.TP {
			    set next [gets $manual(infp)]


			    if {"$next" != {'}} {
				lappend manual(text) ".IP [process-text $next]"
			    }
			}
			.OP {
			    lappend manual(text) [concat .OP [process-text \
				    "\\fB[lindex $rest 0]\\fR \\fB[lindex $rest 1]\\fR \\fB[lindex $rest 2]\\fR"]]







|
>
>







1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
			    lappend manual(text) [concat .IP [process-text "[lindex $rest 0] \\fB[lindex $rest 1]\\fR ([lindex $rest 2])"]]
			}
			.IP {
			    regexp {^(.*) +\d+$} $rest all rest
			    lappend manual(text) ".IP [process-text [unquote [string trim $rest]]]"
			}
			.TP {
			    while {[is-a-directive [set next [gets $manual(infp)]]]} {
			    	manerror "ignoring $next after .TP"
			    }
			    if {"$next" != {'}} {
				lappend manual(text) ".IP [process-text $next]"
			    }
			}
			.OP {
			    lappend manual(text) [concat .OP [process-text \
				    "\\fB[lindex $rest 0]\\fR \\fB[lindex $rest 1]\\fR \\fB[lindex $rest 2]\\fR"]]
Changes to unix/Makefile.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#
# This file is a Makefile for Tcl.  If it has the name "Makefile.in"
# then it is a template for a Makefile;  to generate the actual Makefile,
# run "./configure", which is a configuration script generated by the
# "autoconf" program (constructs like "@foo@" will get replaced in the
# actual Makefile.
#
# RCS: @(#) $Id: Makefile.in,v 1.127.2.3 2003/08/07 21:36:04 dgp Exp $

VERSION 		= @TCL_VERSION@
MAJOR_VERSION		= @TCL_MAJOR_VERSION@
MINOR_VERSION		= @TCL_MINOR_VERSION@
PATCH_LEVEL		= @TCL_PATCH_LEVEL@

#----------------------------------------------------------------







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#
# This file is a Makefile for Tcl.  If it has the name "Makefile.in"
# then it is a template for a Makefile;  to generate the actual Makefile,
# run "./configure", which is a configuration script generated by the
# "autoconf" program (constructs like "@foo@" will get replaced in the
# actual Makefile.
#
# RCS: @(#) $Id: Makefile.in,v 1.127.2.4 2004/02/07 05:48:03 dgp Exp $

VERSION 		= @TCL_VERSION@
MAJOR_VERSION		= @TCL_MAJOR_VERSION@
MINOR_VERSION		= @TCL_MINOR_VERSION@
PATCH_LEVEL		= @TCL_PATCH_LEVEL@

#----------------------------------------------------------------
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
	    if [ ! -d $$i ] ; then \
		echo "Making directory $$i"; \
		mkdir -p $$i; \
		chmod 755 $$i; \
		else true; \
		fi; \
	    done;
	@for i in http2.4 http1.0 opt0.4 encoding msgcat1.3 tcltest2.2; \
	    do \
	    if [ ! -d $(SCRIPT_INSTALL_DIR)/$$i ] ; then \
		echo "Making directory $(SCRIPT_INSTALL_DIR)/$$i"; \
		mkdir -p $(SCRIPT_INSTALL_DIR)/$$i; \
		chmod 755 $(SCRIPT_INSTALL_DIR)/$$i; \
		else true; \
		fi; \







|







628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
	    if [ ! -d $$i ] ; then \
		echo "Making directory $$i"; \
		mkdir -p $$i; \
		chmod 755 $$i; \
		else true; \
		fi; \
	    done;
	@for i in http2.4 http1.0 opt0.4 encoding msgcat1.4 tcltest2.2; \
	    do \
	    if [ ! -d $(SCRIPT_INSTALL_DIR)/$$i ] ; then \
		echo "Making directory $(SCRIPT_INSTALL_DIR)/$$i"; \
		mkdir -p $(SCRIPT_INSTALL_DIR)/$$i; \
		chmod 755 $(SCRIPT_INSTALL_DIR)/$$i; \
		else true; \
		fi; \
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
	    $(INSTALL_DATA) $$j $(SCRIPT_INSTALL_DIR)/http2.4; \
	    done;
	@echo "Installing library opt0.4 directory";
	@for j in $(TOP_DIR)/library/opt/*.tcl ; \
	    do \
	    $(INSTALL_DATA) $$j $(SCRIPT_INSTALL_DIR)/opt0.4; \
	    done;
	@echo "Installing library msgcat1.3 directory";
	@for j in $(TOP_DIR)/library/msgcat/*.tcl ; \
	    do \
	    $(INSTALL_DATA) $$j $(SCRIPT_INSTALL_DIR)/msgcat1.3; \
	    done;
	@echo "Installing library tcltest2.2 directory";
	@for j in $(TOP_DIR)/library/tcltest/*.tcl ; \
	    do \
	    $(INSTALL_DATA) $$j $(SCRIPT_INSTALL_DIR)/tcltest2.2; \
	    done;
	@echo "Installing library encoding directory";







|


|







666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
	    $(INSTALL_DATA) $$j $(SCRIPT_INSTALL_DIR)/http2.4; \
	    done;
	@echo "Installing library opt0.4 directory";
	@for j in $(TOP_DIR)/library/opt/*.tcl ; \
	    do \
	    $(INSTALL_DATA) $$j $(SCRIPT_INSTALL_DIR)/opt0.4; \
	    done;
	@echo "Installing library msgcat1.4 directory";
	@for j in $(TOP_DIR)/library/msgcat/*.tcl ; \
	    do \
	    $(INSTALL_DATA) $$j $(SCRIPT_INSTALL_DIR)/msgcat1.4; \
	    done;
	@echo "Installing library tcltest2.2 directory";
	@for j in $(TOP_DIR)/library/tcltest/*.tcl ; \
	    do \
	    $(INSTALL_DATA) $$j $(SCRIPT_INSTALL_DIR)/tcltest2.2; \
	    done;
	@echo "Installing library encoding directory";
Changes to unix/configure.
10896
10897
10898
10899
10900
10901
10902
10903
10904
10905
10906
10907
10908
10909
10910
10911
10912
10913
10914
10915
10916
10917
10918
10919
10920
10921
10922
10923
10924
10925
10926


10927
10928
10929
10930
10931
10932
10933
10934
10935
10936
10937
10938
10939
10940
10941
10942
10943
10944
10945
10946




















10947
10948
10949
10950
10951
10952
10953
10954
10955
10956
10957
10958
10959
10960
10961
10962
10963
10964
10965
10966
10967
10968
10969
10970
10971
10972
10973
10974
10975
10976
















10977
10978
10979
10980
10981
10982
10983
		fi
		echo "$as_me:$LINENO: result: Using $CC for compiling with threads" >&5
echo "${ECHO_T}Using $CC for compiling with threads" >&6
	    fi
	    LIBS="$LIBS -lc"
	    # AIX-5 uses ELF style dynamic libraries
	    SHLIB_CFLAGS=""
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"
	    if test "`uname -m`" = "ia64" ; then
		# AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC
		SHLIB_LD="/usr/ccs/bin/ld -G -z text"
		# AIX-5 has dl* in libc.so
		DL_LIBS=""
		if test "$GCC" = "yes" ; then
		    CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
		else
		    CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}'
		fi
		LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}'
	    else
		SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry"
		DL_LIBS="-ldl"
		CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
		TCL_NEEDS_EXP_FILE=1
		TCL_EXPORT_FILE_SUFFIX='${VERSION}\$\{DBGX\}.exp'
	    fi

	    # Note: need the LIBS below, otherwise Tk won't find Tcl's
	    # symbols when dynamically loaded into tclsh.



	    DL_OBJS="tclLoadDl.o"
	    LDFLAGS=""

	    LD_LIBRARY_PATH_VAR="LIBPATH"

	    # Check to enable 64-bit flags for compiler/linker
	    if test "$do64bit" = "yes" ; then
		if test "$GCC" = "yes" ; then
		    { echo "$as_me:$LINENO: WARNING: \"64bit mode not supported with GCC on $system\"" >&5
echo "$as_me: WARNING: \"64bit mode not supported with GCC on $system\"" >&2;}
		else
		    do64bit_ok=yes
		    EXTRA_CFLAGS="-q64"
		    LDFLAGS="-q64"
		    RANLIB="${RANLIB} -X64"
		    AR="${AR} -X64"
		    SHLIB_LD_FLAGS="-b64"
		fi
	    fi




















	    ;;
	AIX-*)
	    if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes" ; then
		# AIX requires the _r compiler when gcc isn't being used
		if test "${CC}" != "cc_r" ; then
		    CC=${CC}_r
		fi
		echo "$as_me:$LINENO: result: Using $CC for compiling with threads" >&5
echo "${ECHO_T}Using $CC for compiling with threads" >&6
	    fi
	    LIBS="$LIBS -lc"
	    SHLIB_CFLAGS=""
	    SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-ldl"
	    LDFLAGS=""
	    CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    LD_LIBRARY_PATH_VAR="LIBPATH"
	    TCL_NEEDS_EXP_FILE=1
	    TCL_EXPORT_FILE_SUFFIX='${VERSION}\$\{DBGX\}.exp'

	    # AIX v<=4.1 has some different flags than 4.2+
	    if test "$system" = "AIX-4.1" -o "`uname -v`" -lt "4" ; then
		LIBOBJS="$LIBOBJS tclLoadAix.$ac_objext"
		DL_LIBS="-lld"
	    fi

















	    # On AIX <=v4 systems, libbsd.a has to be linked in to support
	    # non-blocking file IO.  This library has to be linked in after
	    # the MATH_LIBS or it breaks the pow() function.  The way to
	    # insure proper sequencing, is to add it to the tail of MATH_LIBS.
	    # This library also supplies gettimeofday.
	    #
	    # AIX does not have a timezone field in struct tm. When the AIX







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


>
>




















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












<

















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







10896
10897
10898
10899
10900
10901
10902






















10903
10904
10905
10906
10907
10908
10909
10910
10911
10912
10913
10914
10915
10916
10917
10918
10919
10920
10921
10922
10923
10924
10925
10926
10927
10928
10929
10930
10931
10932
10933
10934
10935
10936
10937
10938
10939
10940
10941
10942
10943
10944
10945
10946
10947
10948
10949
10950
10951
10952
10953
10954
10955
10956
10957
10958

10959
10960
10961
10962
10963
10964
10965
10966
10967
10968
10969
10970
10971
10972
10973
10974
10975
10976
10977
10978
10979
10980
10981
10982
10983
10984
10985
10986
10987
10988
10989
10990
10991
10992
10993
10994
10995
10996
10997
10998
		fi
		echo "$as_me:$LINENO: result: Using $CC for compiling with threads" >&5
echo "${ECHO_T}Using $CC for compiling with threads" >&6
	    fi
	    LIBS="$LIBS -lc"
	    # AIX-5 uses ELF style dynamic libraries
	    SHLIB_CFLAGS=""






















	    # Note: need the LIBS below, otherwise Tk won't find Tcl's
	    # symbols when dynamically loaded into tclsh.
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"

	    DL_OBJS="tclLoadDl.o"
	    LDFLAGS=""

	    LD_LIBRARY_PATH_VAR="LIBPATH"

	    # Check to enable 64-bit flags for compiler/linker
	    if test "$do64bit" = "yes" ; then
		if test "$GCC" = "yes" ; then
		    { echo "$as_me:$LINENO: WARNING: \"64bit mode not supported with GCC on $system\"" >&5
echo "$as_me: WARNING: \"64bit mode not supported with GCC on $system\"" >&2;}
		else
		    do64bit_ok=yes
		    EXTRA_CFLAGS="-q64"
		    LDFLAGS="-q64"
		    RANLIB="${RANLIB} -X64"
		    AR="${AR} -X64"
		    SHLIB_LD_FLAGS="-b64"
		fi
	    fi

	    if test "`uname -m`" = "ia64" ; then
		# AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC
		SHLIB_LD="/usr/ccs/bin/ld -G -z text"
		# AIX-5 has dl* in libc.so
		DL_LIBS=""
		if test "$GCC" = "yes" ; then
		    CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
		else
		    CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}'
		fi
		LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}'
	    else
		SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry ${SHLIB_LD_FLAGS}"
		DL_LIBS="-ldl"
		CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
		TCL_NEEDS_EXP_FILE=1
		TCL_EXPORT_FILE_SUFFIX='${VERSION}\$\{DBGX\}.exp'
	    fi
	    ;;
	AIX-*)
	    if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes" ; then
		# AIX requires the _r compiler when gcc isn't being used
		if test "${CC}" != "cc_r" ; then
		    CC=${CC}_r
		fi
		echo "$as_me:$LINENO: result: Using $CC for compiling with threads" >&5
echo "${ECHO_T}Using $CC for compiling with threads" >&6
	    fi
	    LIBS="$LIBS -lc"
	    SHLIB_CFLAGS=""

	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-ldl"
	    LDFLAGS=""
	    CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    LD_LIBRARY_PATH_VAR="LIBPATH"
	    TCL_NEEDS_EXP_FILE=1
	    TCL_EXPORT_FILE_SUFFIX='${VERSION}\$\{DBGX\}.exp'

	    # AIX v<=4.1 has some different flags than 4.2+
	    if test "$system" = "AIX-4.1" -o "`uname -v`" -lt "4" ; then
		LIBOBJS="$LIBOBJS tclLoadAix.$ac_objext"
		DL_LIBS="-lld"
	    fi

	    # Check to enable 64-bit flags for compiler/linker
	    if test "$do64bit" = "yes" ; then
		if test "$GCC" = "yes" ; then
		    { echo "$as_me:$LINENO: WARNING: \"64bit mode not supported with GCC on $system\"" >&5
echo "$as_me: WARNING: \"64bit mode not supported with GCC on $system\"" >&2;}
		else
		    do64bit_ok=yes
		    EXTRA_CFLAGS="-q64"
		    LDFLAGS="-q64"
		    RANLIB="${RANLIB} -X64"
		    AR="${AR} -X64"
		    SHLIB_LD_FLAGS="-b64"
		fi
	    fi
	    SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry ${SHLIB_LD_FLAGS}"

	    # On AIX <=v4 systems, libbsd.a has to be linked in to support
	    # non-blocking file IO.  This library has to be linked in after
	    # the MATH_LIBS or it breaks the pow() function.  The way to
	    # insure proper sequencing, is to add it to the tail of MATH_LIBS.
	    # This library also supplies gettimeofday.
	    #
	    # AIX does not have a timezone field in struct tm. When the AIX
11048
11049
11050
11051
11052
11053
11054
11055
11056
11057
11058
11059
11060
11061
11062
11063
11064
11065
11066
11067
11068
11069
11070
11071
11072
11073
11074
11075
11076

	    if test $libbsd = yes; then
	    	MATH_LIBS="$MATH_LIBS -lbsd"
	    	cat >>confdefs.h <<\_ACEOF
#define USE_DELTA_FOR_TZ 1
_ACEOF

	    fi

	    # Check to enable 64-bit flags for compiler/linker
	    if test "$do64bit" = "yes" ; then
		if test "$GCC" = "yes" ; then
		    { echo "$as_me:$LINENO: WARNING: \"64bit mode not supported with GCC on $system\"" >&5
echo "$as_me: WARNING: \"64bit mode not supported with GCC on $system\"" >&2;}
		else
		    do64bit_ok=yes
		    EXTRA_CFLAGS="-q64"
		    LDFLAGS="-q64"
		    RANLIB="${RANLIB} -X64"
		    AR="${AR} -X64"
		    SHLIB_LD_FLAGS="-b64"
		fi
	    fi
	    ;;
	BeOS*)
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD="${CC} -nostart"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"







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







11063
11064
11065
11066
11067
11068
11069















11070
11071
11072
11073
11074
11075
11076

	    if test $libbsd = yes; then
	    	MATH_LIBS="$MATH_LIBS -lbsd"
	    	cat >>confdefs.h <<\_ACEOF
#define USE_DELTA_FOR_TZ 1
_ACEOF
















	    fi
	    ;;
	BeOS*)
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD="${CC} -nostart"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"
11442
11443
11444
11445
11446
11447
11448

11449
11450
11451
11452
11453
11454
11455
11456
11457
11458
11459
11460
	    fi
	    ;;
	Linux*)
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"


	    # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings
	    # when you inline the string and math operations.  Turn this off to
	    # get rid of the warnings.

	    CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES"

	    if test "$have_dl" = yes; then
		SHLIB_LD="${CC} -shared"
		DL_OBJS="tclLoadDl.o"
		DL_LIBS="-ldl"
		LDFLAGS="-Wl,--export-dynamic"
		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'







>



<
|







11442
11443
11444
11445
11446
11447
11448
11449
11450
11451
11452

11453
11454
11455
11456
11457
11458
11459
11460
	    fi
	    ;;
	Linux*)
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"

	    CFLAGS_OPTIMIZE=-O2
	    # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings
	    # when you inline the string and math operations.  Turn this off to
	    # get rid of the warnings.

	    #CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES"

	    if test "$have_dl" = yes; then
		SHLIB_LD="${CC} -shared"
		DL_OBJS="tclLoadDl.o"
		DL_LIBS="-ldl"
		LDFLAGS="-Wl,--export-dynamic"
		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
11799
11800
11801
11802
11803
11804
11805
11806
11807
11808
11809
11810
11811
11812
11813
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-ldl"
	    LDFLAGS="-Wl,-Bexport"
	    CC_SEARCH_FLAGS=""
	    LD_SEARCH_FLAGS=""
	    ;;
	NetBSD-*|FreeBSD-[1-2].*|OpenBSD-*)
	    # Not available on all versions:  check for include file.
	    if test "${ac_cv_header_dlfcn_h+set}" = set; then
  echo "$as_me:$LINENO: checking for dlfcn.h" >&5
echo $ECHO_N "checking for dlfcn.h... $ECHO_C" >&6
if test "${ac_cv_header_dlfcn_h+set}" = set; then
  echo $ECHO_N "(cached) $ECHO_C" >&6
fi







|







11799
11800
11801
11802
11803
11804
11805
11806
11807
11808
11809
11810
11811
11812
11813
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-ldl"
	    LDFLAGS="-Wl,-Bexport"
	    CC_SEARCH_FLAGS=""
	    LD_SEARCH_FLAGS=""
	    ;;
	NetBSD-*|FreeBSD-[1-2].*)
	    # Not available on all versions:  check for include file.
	    if test "${ac_cv_header_dlfcn_h+set}" = set; then
  echo "$as_me:$LINENO: checking for dlfcn.h" >&5
echo $ECHO_N "checking for dlfcn.h... $ECHO_C" >&6
if test "${ac_cv_header_dlfcn_h+set}" = set; then
  echo $ECHO_N "(cached) $ECHO_C" >&6
fi
11993
11994
11995
11996
11997
11998
11999










































12000
12001
12002
12003
12004
12005
12006


	    # FreeBSD doesn't handle version numbers with dots.

	    UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a'
	    TCL_LIB_VERSIONS_OK=nodots
	    ;;










































	FreeBSD-*)
	    # FreeBSD 3.* and greater have ELF.
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD="ld -Bshareable -x"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"







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







11993
11994
11995
11996
11997
11998
11999
12000
12001
12002
12003
12004
12005
12006
12007
12008
12009
12010
12011
12012
12013
12014
12015
12016
12017
12018
12019
12020
12021
12022
12023
12024
12025
12026
12027
12028
12029
12030
12031
12032
12033
12034
12035
12036
12037
12038
12039
12040
12041
12042
12043
12044
12045
12046
12047
12048


	    # FreeBSD doesn't handle version numbers with dots.

	    UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a'
	    TCL_LIB_VERSIONS_OK=nodots
	    ;;
	OpenBSD-*)
	    SHLIB_LD="${CC} -shared"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    LDFLAGS=""
	    CC_SEARCH_FLAGS=""
	    LD_SEARCH_FLAGS=""
	    echo "$as_me:$LINENO: checking for ELF" >&5
echo $ECHO_N "checking for ELF... $ECHO_C" >&6
	    cat >conftest.$ac_ext <<_ACEOF
#line $LINENO "configure"
/* confdefs.h.  */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h.  */

#ifdef __ELF__
	yes
#endif

_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
  $EGREP "yes" >/dev/null 2>&1; then
  echo "$as_me:$LINENO: result: yes" >&5
echo "${ECHO_T}yes" >&6
		SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1.0'
else
  echo "$as_me:$LINENO: result: no" >&5
echo "${ECHO_T}no" >&6
		SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1.0'

fi
rm -f conftest*


	    # OpenBSD doesn't do version numbers with dots.
	    UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a'
	    TCL_LIB_VERSIONS_OK=nodots
	    ;;
	FreeBSD-*)
	    # FreeBSD 3.* and greater have ELF.
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD="ld -Bshareable -x"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
12613
12614
12615
12616
12617
12618
12619
12620
12621
12622
12623
12624
12625
12626
12627
	    case $system in
		AIX-*)
		    ;;
		BSD/OS*)
		    ;;
		IRIX*)
		    ;;
		NetBSD-*|FreeBSD-*|OpenBSD-*)
		    ;;
		Rhapsody-*|Darwin-*)
		    ;;
		RISCos-*)
		    ;;
		SCO_SV-3.2*)
		    ;;







|







12655
12656
12657
12658
12659
12660
12661
12662
12663
12664
12665
12666
12667
12668
12669
	    case $system in
		AIX-*)
		    ;;
		BSD/OS*)
		    ;;
		IRIX*)
		    ;;
		NetBSD-*|FreeBSD-*)
		    ;;
		Rhapsody-*|Darwin-*)
		    ;;
		RISCos-*)
		    ;;
		SCO_SV-3.2*)
		    ;;
Changes to unix/mkLinks.
1663
1664
1665
1666
1667
1668
1669




1670
1671
1672
1673
1674
1675
1676
if test -r join.n; then
    rm -f join.n.*
    $ZIP join.n
fi
if test -r lappend.n; then
    rm -f lappend.n.*
    $ZIP lappend.n




fi
if test -r library.n; then
    rm -f library.n.*
    $ZIP library.n
    rm -f auto_execok.n auto_execok.n.* 
    rm -f auto_import.n auto_import.n.* 
    rm -f auto_load.n auto_load.n.* 







>
>
>
>







1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
if test -r join.n; then
    rm -f join.n.*
    $ZIP join.n
fi
if test -r lappend.n; then
    rm -f lappend.n.*
    $ZIP lappend.n
fi
if test -r lassign.n; then
    rm -f lassign.n.*
    $ZIP lassign.n
fi
if test -r library.n; then
    rm -f library.n.*
    $ZIP library.n
    rm -f auto_execok.n auto_execok.n.* 
    rm -f auto_import.n auto_import.n.* 
    rm -f auto_load.n auto_load.n.* 
Changes to unix/tcl.m4.
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
		    CC=${CC}_r
		fi
		AC_MSG_RESULT(Using $CC for compiling with threads)
	    fi
	    LIBS="$LIBS -lc"
	    # AIX-5 uses ELF style dynamic libraries
	    SHLIB_CFLAGS=""
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"
	    if test "`uname -m`" = "ia64" ; then
		# AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC
		SHLIB_LD="/usr/ccs/bin/ld -G -z text"
		# AIX-5 has dl* in libc.so
		DL_LIBS=""
		if test "$GCC" = "yes" ; then
		    CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
		else
		    CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}'
		fi
		LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}'
	    else
		SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry"
		DL_LIBS="-ldl"
		CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
		TCL_NEEDS_EXP_FILE=1
		TCL_EXPORT_FILE_SUFFIX='${VERSION}\$\{DBGX\}.exp'
	    fi

	    # Note: need the LIBS below, otherwise Tk won't find Tcl's
	    # symbols when dynamically loaded into tclsh.



	    DL_OBJS="tclLoadDl.o"
	    LDFLAGS=""

	    LD_LIBRARY_PATH_VAR="LIBPATH"

	    # Check to enable 64-bit flags for compiler/linker
	    if test "$do64bit" = "yes" ; then
		if test "$GCC" = "yes" ; then
		    AC_MSG_WARN("64bit mode not supported with GCC on $system")
		else 
		    do64bit_ok=yes
		    EXTRA_CFLAGS="-q64"
		    LDFLAGS="-q64"
		    RANLIB="${RANLIB} -X64"
		    AR="${AR} -X64"
		    SHLIB_LD_FLAGS="-b64"
		fi
	    fi




















	    ;;
	AIX-*)
	    if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes" ; then
		# AIX requires the _r compiler when gcc isn't being used
		if test "${CC}" != "cc_r" ; then
		    CC=${CC}_r
		fi
		AC_MSG_RESULT(Using $CC for compiling with threads)
	    fi
	    LIBS="$LIBS -lc"
	    SHLIB_CFLAGS=""
	    SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-ldl"
	    LDFLAGS=""
	    CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    LD_LIBRARY_PATH_VAR="LIBPATH"
	    TCL_NEEDS_EXP_FILE=1
	    TCL_EXPORT_FILE_SUFFIX='${VERSION}\$\{DBGX\}.exp'

	    # AIX v<=4.1 has some different flags than 4.2+
	    if test "$system" = "AIX-4.1" -o "`uname -v`" -lt "4" ; then
		AC_LIBOBJ([tclLoadAix])
		DL_LIBS="-lld"
	    fi
















	    # On AIX <=v4 systems, libbsd.a has to be linked in to support
	    # non-blocking file IO.  This library has to be linked in after
	    # the MATH_LIBS or it breaks the pow() function.  The way to
	    # insure proper sequencing, is to add it to the tail of MATH_LIBS.
	    # This library also supplies gettimeofday.
	    #
	    # AIX does not have a timezone field in struct tm. When the AIX
	    # bsd library is used, the timezone global and the gettimeofday
	    # methods are to be avoided for timezone deduction instead, we
	    # deduce the timezone by comparing the localtime result on a
	    # known GMT value.

	    AC_CHECK_LIB(bsd, gettimeofday, libbsd=yes, libbsd=no)
	    if test $libbsd = yes; then
	    	MATH_LIBS="$MATH_LIBS -lbsd"
	    	AC_DEFINE(USE_DELTA_FOR_TZ)
	    fi

	    # Check to enable 64-bit flags for compiler/linker
	    if test "$do64bit" = "yes" ; then
		if test "$GCC" = "yes" ; then
		    AC_MSG_WARN("64bit mode not supported with GCC on $system")
		else 
		    do64bit_ok=yes
		    EXTRA_CFLAGS="-q64"
		    LDFLAGS="-q64"
		    RANLIB="${RANLIB} -X64"
		    AR="${AR} -X64"
		    SHLIB_LD_FLAGS="-b64"
		fi
	    fi
	    ;;
	BeOS*)
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD="${CC} -nostart"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"







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


>
>



















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











<

















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
















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







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
		    CC=${CC}_r
		fi
		AC_MSG_RESULT(Using $CC for compiling with threads)
	    fi
	    LIBS="$LIBS -lc"
	    # AIX-5 uses ELF style dynamic libraries
	    SHLIB_CFLAGS=""






















	    # Note: need the LIBS below, otherwise Tk won't find Tcl's
	    # symbols when dynamically loaded into tclsh.
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"

	    DL_OBJS="tclLoadDl.o"
	    LDFLAGS=""

	    LD_LIBRARY_PATH_VAR="LIBPATH"

	    # Check to enable 64-bit flags for compiler/linker
	    if test "$do64bit" = "yes" ; then
		if test "$GCC" = "yes" ; then
		    AC_MSG_WARN("64bit mode not supported with GCC on $system")
		else 
		    do64bit_ok=yes
		    EXTRA_CFLAGS="-q64"
		    LDFLAGS="-q64"
		    RANLIB="${RANLIB} -X64"
		    AR="${AR} -X64"
		    SHLIB_LD_FLAGS="-b64"
		fi
	    fi

	    if test "`uname -m`" = "ia64" ; then
		# AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC
		SHLIB_LD="/usr/ccs/bin/ld -G -z text"
		# AIX-5 has dl* in libc.so
		DL_LIBS=""
		if test "$GCC" = "yes" ; then
		    CC_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}'
		else
		    CC_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}'
		fi
		LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}'
	    else
		SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry ${SHLIB_LD_FLAGS}"
		DL_LIBS="-ldl"
		CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
		LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
		TCL_NEEDS_EXP_FILE=1
		TCL_EXPORT_FILE_SUFFIX='${VERSION}\$\{DBGX\}.exp'
	    fi
	    ;;
	AIX-*)
	    if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes" ; then
		# AIX requires the _r compiler when gcc isn't being used
		if test "${CC}" != "cc_r" ; then
		    CC=${CC}_r
		fi
		AC_MSG_RESULT(Using $CC for compiling with threads)
	    fi
	    LIBS="$LIBS -lc"
	    SHLIB_CFLAGS=""

	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-ldl"
	    LDFLAGS=""
	    CC_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}'
	    LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS}
	    LD_LIBRARY_PATH_VAR="LIBPATH"
	    TCL_NEEDS_EXP_FILE=1
	    TCL_EXPORT_FILE_SUFFIX='${VERSION}\$\{DBGX\}.exp'

	    # AIX v<=4.1 has some different flags than 4.2+
	    if test "$system" = "AIX-4.1" -o "`uname -v`" -lt "4" ; then
		AC_LIBOBJ([tclLoadAix])
		DL_LIBS="-lld"
	    fi

	    # Check to enable 64-bit flags for compiler/linker
	    if test "$do64bit" = "yes" ; then
		if test "$GCC" = "yes" ; then
		    AC_MSG_WARN("64bit mode not supported with GCC on $system")
		else 
		    do64bit_ok=yes
		    EXTRA_CFLAGS="-q64"
		    LDFLAGS="-q64"
		    RANLIB="${RANLIB} -X64"
		    AR="${AR} -X64"
		    SHLIB_LD_FLAGS="-b64"
		fi
	    fi
	    SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix /bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry ${SHLIB_LD_FLAGS}"

	    # On AIX <=v4 systems, libbsd.a has to be linked in to support
	    # non-blocking file IO.  This library has to be linked in after
	    # the MATH_LIBS or it breaks the pow() function.  The way to
	    # insure proper sequencing, is to add it to the tail of MATH_LIBS.
	    # This library also supplies gettimeofday.
	    #
	    # AIX does not have a timezone field in struct tm. When the AIX
	    # bsd library is used, the timezone global and the gettimeofday
	    # methods are to be avoided for timezone deduction instead, we
	    # deduce the timezone by comparing the localtime result on a
	    # known GMT value.

	    AC_CHECK_LIB(bsd, gettimeofday, libbsd=yes, libbsd=no)
	    if test $libbsd = yes; then
	    	MATH_LIBS="$MATH_LIBS -lbsd"
	    	AC_DEFINE(USE_DELTA_FOR_TZ)














	    fi
	    ;;
	BeOS*)
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD="${CC} -nostart"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"
1130
1131
1132
1133
1134
1135
1136

1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
	    fi
	    ;;
	Linux*)
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"


	    # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings 
	    # when you inline the string and math operations.  Turn this off to
	    # get rid of the warnings.

	    CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES"

	    if test "$have_dl" = yes; then
		SHLIB_LD="${CC} -shared"
		DL_OBJS="tclLoadDl.o"
		DL_LIBS="-ldl"
		LDFLAGS="-Wl,--export-dynamic"
		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'







>



<
|







1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140

1141
1142
1143
1144
1145
1146
1147
1148
	    fi
	    ;;
	Linux*)
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"

	    CFLAGS_OPTIMIZE=-O2
	    # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings 
	    # when you inline the string and math operations.  Turn this off to
	    # get rid of the warnings.

	    #CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES"

	    if test "$have_dl" = yes; then
		SHLIB_LD="${CC} -shared"
		DL_OBJS="tclLoadDl.o"
		DL_LIBS="-ldl"
		LDFLAGS="-Wl,--export-dynamic"
		CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}'
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-ldl"
	    LDFLAGS="-Wl,-Bexport"
	    CC_SEARCH_FLAGS=""
	    LD_SEARCH_FLAGS=""
	    ;;
	NetBSD-*|FreeBSD-[[1-2]].*|OpenBSD-*)
	    # Not available on all versions:  check for include file.
	    AC_CHECK_HEADER(dlfcn.h, [
		# NetBSD/SPARC needs -fPIC, -fpic will not do.
		SHLIB_CFLAGS="-fPIC"
		SHLIB_LD="ld -Bshareable -x"
		SHLIB_LD_LIBS=""
		SHLIB_SUFFIX=".so"







|







1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS="-ldl"
	    LDFLAGS="-Wl,-Bexport"
	    CC_SEARCH_FLAGS=""
	    LD_SEARCH_FLAGS=""
	    ;;
	NetBSD-*|FreeBSD-[[1-2]].*)
	    # Not available on all versions:  check for include file.
	    AC_CHECK_HEADER(dlfcn.h, [
		# NetBSD/SPARC needs -fPIC, -fpic will not do.
		SHLIB_CFLAGS="-fPIC"
		SHLIB_LD="ld -Bshareable -x"
		SHLIB_LD_LIBS=""
		SHLIB_SUFFIX=".so"
1260
1261
1262
1263
1264
1265
1266

























1267
1268
1269
1270
1271
1272
1273
	    ])

	    # FreeBSD doesn't handle version numbers with dots.

	    UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a'
	    TCL_LIB_VERSIONS_OK=nodots
	    ;;

























	FreeBSD-*)
	    # FreeBSD 3.* and greater have ELF.
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD="ld -Bshareable -x"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"







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







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
	    ])

	    # FreeBSD doesn't handle version numbers with dots.

	    UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a'
	    TCL_LIB_VERSIONS_OK=nodots
	    ;;
	OpenBSD-*)
	    SHLIB_LD="${CC} -shared"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
	    DL_LIBS=""
	    LDFLAGS=""
	    CC_SEARCH_FLAGS=""
	    LD_SEARCH_FLAGS=""
	    AC_MSG_CHECKING(for ELF)
	    AC_EGREP_CPP(yes, [
#ifdef __ELF__
	yes
#endif
	    ],
		[AC_MSG_RESULT(yes)
		SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1.0'],
		[AC_MSG_RESULT(no)
		SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.so.1.0']
	    )

	    # OpenBSD doesn't do version numbers with dots.
	    UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}\$\{DBGX\}.a'
	    TCL_LIB_VERSIONS_OK=nodots
	    ;;
	FreeBSD-*)
	    # FreeBSD 3.* and greater have ELF.
	    SHLIB_CFLAGS="-fPIC"
	    SHLIB_LD="ld -Bshareable -x"
	    SHLIB_LD_LIBS='${LIBS}'
	    SHLIB_SUFFIX=".so"
	    DL_OBJS="tclLoadDl.o"
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
	    case $system in
		AIX-*)
		    ;;
		BSD/OS*)
		    ;;
		IRIX*)
		    ;;
		NetBSD-*|FreeBSD-*|OpenBSD-*)
		    ;;
		Rhapsody-*|Darwin-*)
		    ;;
		RISCos-*)
		    ;;
		SCO_SV-3.2*)
		    ;;







|







1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
	    case $system in
		AIX-*)
		    ;;
		BSD/OS*)
		    ;;
		IRIX*)
		    ;;
		NetBSD-*|FreeBSD-*)
		    ;;
		Rhapsody-*|Darwin-*)
		    ;;
		RISCos-*)
		    ;;
		SCO_SV-3.2*)
		    ;;
Changes to unix/tclUnixChan.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclUnixChan.c
 *
 *	Common channel driver for Unix channels based on files, command
 *	pipes and TCP sockets.
 *
 * Copyright (c) 1995-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.
 *
 * RCS: @(#) $Id: tclUnixChan.c,v 1.42 2003/02/21 02:36:27 hobbs Exp $
 */

#include "tclInt.h"	/* Internal definitions for Tcl. */
#include "tclPort.h"	/* Portability features for Tcl. */
#include "tclIO.h"	/* To get Channel type declaration. */

/*












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclUnixChan.c
 *
 *	Common channel driver for Unix channels based on files, command
 *	pipes and TCP sockets.
 *
 * Copyright (c) 1995-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.
 *
 * RCS: @(#) $Id: tclUnixChan.c,v 1.42.4.1 2004/02/07 05:48:04 dgp Exp $
 */

#include "tclInt.h"	/* Internal definitions for Tcl. */
#include "tclPort.h"	/* Portability features for Tcl. */
#include "tclIO.h"	/* To get Channel type declaration. */

/*
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787



1788
1789
1790
1791
1792
1793
1794
	case O_RDWR:
	    channelPermissions = (TCL_READABLE | TCL_WRITABLE);
	    break;
	default:
	    /*
	     * This may occurr if modeString was "", for example.
	     */
	    panic("TclpOpenFileChannel: invalid mode value");
	    return NULL;
    }

    native = Tcl_FSGetNativePath(pathPtr);
    if (native == NULL) {
	return NULL;
    }



    fd = TclOSopen(native, mode, permissions);
#ifdef SUPPORTS_TTY
    ctl_tty = (strcmp (native, "/dev/tty") == 0);
#endif /* SUPPORTS_TTY */

    if (fd < 0) {
	if (interp != (Tcl_Interp *) NULL) {







|







>
>
>







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
	case O_RDWR:
	    channelPermissions = (TCL_READABLE | TCL_WRITABLE);
	    break;
	default:
	    /*
	     * This may occurr if modeString was "", for example.
	     */
	    Tcl_Panic("TclpOpenFileChannel: invalid mode value");
	    return NULL;
    }

    native = Tcl_FSGetNativePath(pathPtr);
    if (native == NULL) {
	return NULL;
    }
#ifdef DJGPP
	mode |= O_BINARY;
#endif		
    fd = TclOSopen(native, mode, permissions);
#ifdef SUPPORTS_TTY
    ctl_tty = (strcmp (native, "/dev/tty") == 0);
#endif /* SUPPORTS_TTY */

    if (fd < 0) {
	if (interp != (Tcl_Interp *) NULL) {
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
    FileState *fsPtr;
    char channelName[16 + TCL_INTEGER_SPACE];
    int fd = (int) handle;
    Tcl_ChannelType *channelTypePtr;
#ifdef DEPRECATED
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
#endif /* DEPRECATED */
    int socketType = 0;
    socklen_t argLength = sizeof(int);

    if (mode == 0) {
	return NULL;
    }


    /*
     * Look to see if a channel with this fd and the same mode already exists.
     * If the fd is used, but the mode doesn't match, return NULL.
     */

#ifdef DEPRECATED
    for (fsPtr = tsdPtr->firstFilePtr; fsPtr != NULL; fsPtr = fsPtr->nextPtr) {
	if (fsPtr->fd == fd) {
	    return ((mode|TCL_EXCEPTION) == fsPtr->validMask) ?
		    fsPtr->channel : NULL;
	}
    }
#endif /* DEPRECATED */



#ifdef SUPPORTS_TTY
    if (isatty(fd)) {
	fsPtr = TtyInit(fd, 0);
	channelTypePtr = &ttyChannelType;
	sprintf(channelName, "serial%d", fd);
    } else
#endif /* SUPPORTS_TTY */
    if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (VOID *)&socketType,
		   &argLength) == 0  &&	 socketType == SOCK_STREAM) {

	return MakeTcpClientChannelMode((ClientData) fd, mode);
    } else {
	channelTypePtr = &fileChannelType;
	fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState));
	sprintf(channelName, "file%d", fd);
    }








|
|




















>
>







|
|
>







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
    FileState *fsPtr;
    char channelName[16 + TCL_INTEGER_SPACE];
    int fd = (int) handle;
    Tcl_ChannelType *channelTypePtr;
#ifdef DEPRECATED
    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
#endif /* DEPRECATED */
    struct sockaddr sockaddr;
    socklen_t sockaddrLen = sizeof(sockaddr);

    if (mode == 0) {
	return NULL;
    }


    /*
     * Look to see if a channel with this fd and the same mode already exists.
     * If the fd is used, but the mode doesn't match, return NULL.
     */

#ifdef DEPRECATED
    for (fsPtr = tsdPtr->firstFilePtr; fsPtr != NULL; fsPtr = fsPtr->nextPtr) {
	if (fsPtr->fd == fd) {
	    return ((mode|TCL_EXCEPTION) == fsPtr->validMask) ?
		    fsPtr->channel : NULL;
	}
    }
#endif /* DEPRECATED */

    sockaddr.sa_family = AF_UNSPEC;

#ifdef SUPPORTS_TTY
    if (isatty(fd)) {
	fsPtr = TtyInit(fd, 0);
	channelTypePtr = &ttyChannelType;
	sprintf(channelName, "serial%d", fd);
    } else
#endif /* SUPPORTS_TTY */
    if (getsockname(fd, (struct sockaddr *)&sockaddr, &sockaddrLen) == 0
            && sockaddrLen > 0
            && sockaddr.sa_family == AF_INET) {
	return MakeTcpClientChannelMode((ClientData) fd, mode);
    } else {
	channelTypePtr = &fileChannelType;
	fsPtr = (FileState *) ckalloc((unsigned) sizeof(FileState));
	sprintf(channelName, "file%d", fd);
    }

2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
		return (Tcl_Channel) NULL;
	    }
	    fd = 2;
	    mode = TCL_WRITABLE;
	    bufMode = "none";
	    break;
	default:
	    panic("TclGetDefaultStdChannel: Unexpected channel type");
	    break;
    }

#undef ZERO_OFFSET
#undef ERROR_OFFSET

    channel = Tcl_MakeFileChannel((ClientData) fd, mode);







|







2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
		return (Tcl_Channel) NULL;
	    }
	    fd = 2;
	    mode = TCL_WRITABLE;
	    bufMode = "none";
	    break;
	default:
	    Tcl_Panic("TclGetDefaultStdChannel: Unexpected channel type");
	    break;
    }

#undef ZERO_OFFSET
#undef ERROR_OFFSET

    channel = Tcl_MakeFileChannel((ClientData) fd, mode);
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
    }

    /*
     * Initialize the ready masks and compute the mask offsets.
     */

    if (fd >= FD_SETSIZE) {
	panic("TclWaitForFile can't handle file id %d", fd);
    }
    memset((VOID *) readyMasks, 0, 3*MASK_SIZE*sizeof(fd_mask));
    index = fd/(NBBY*sizeof(fd_mask));
    bit = 1 << (fd%(NBBY*sizeof(fd_mask)));

    /*
     * Loop in a mini-event loop of our own, waiting for either the







|







3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
    }

    /*
     * Initialize the ready masks and compute the mask offsets.
     */

    if (fd >= FD_SETSIZE) {
	Tcl_Panic("TclWaitForFile can't handle file id %d", fd);
    }
    memset((VOID *) readyMasks, 0, 3*MASK_SIZE*sizeof(fd_mask));
    index = fd/(NBBY*sizeof(fd_mask));
    bit = 1 << (fd%(NBBY*sizeof(fd_mask)));

    /*
     * Loop in a mini-event loop of our own, waiting for either the
3313
3314
3315
3316
3317
3318
3319
3320
3321

3322
3323
3324
3325
3326
3327
3328

    /*
     * This could happen if the channel was created in one thread
     * and then moved to another without updating the thread
     * local data in each thread.
     */

    if (!removed)
        panic("file info ptr not on thread channel list");


#endif /* DEPRECATED */
}

/*
 *----------------------------------------------------------------------
 *







|
|
>







3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335

    /*
     * This could happen if the channel was created in one thread
     * and then moved to another without updating the thread
     * local data in each thread.
     */

    if (!removed) {
        Tcl_Panic("file info ptr not on thread channel list");
    }

#endif /* DEPRECATED */
}

/*
 *----------------------------------------------------------------------
 *
Changes to unix/tclUnixFCmd.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
 * tclUnixFCmd.c
 *
 *      This file implements the unix specific portion of file manipulation 
 *      subcommands of the "file" command.  All filename arguments should
 *	already be translated to native format.
 *
 * Copyright (c) 1996-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.
 *
 * RCS: @(#) $Id: tclUnixFCmd.c,v 1.29.2.2 2003/10/16 02:28:03 dgp Exp $
 *
 * Portions of this code were derived from NetBSD source code which has
 * the following copyright notice:
 *
 * Copyright (c) 1988, 1993, 1994
 *      The Regents of the University of California.  All rights reserved.
 *












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
 * tclUnixFCmd.c
 *
 *      This file implements the unix specific portion of file manipulation 
 *      subcommands of the "file" command.  All filename arguments should
 *	already be translated to native format.
 *
 * Copyright (c) 1996-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.
 *
 * RCS: @(#) $Id: tclUnixFCmd.c,v 1.29.2.3 2004/02/07 05:48:04 dgp Exp $
 *
 * Portions of this code were derived from NetBSD source code which has
 * the following copyright notice:
 *
 * Copyright (c) 1988, 1993, 1994
 *      The Regents of the University of California.  All rights reserved.
 *
106
107
108
109
110
111
112




113
114
115
116
117
118
119

typedef int (TraversalProc) _ANSI_ARGS_((Tcl_DString *srcPtr,
	Tcl_DString *dstPtr, CONST Tcl_StatBuf *statBufPtr, int type,
	Tcl_DString *errorPtr));

/*
 * Constants and variables necessary for file attributes subcommand.




 */

enum {
    UNIX_GROUP_ATTRIBUTE,
    UNIX_OWNER_ATTRIBUTE,
    UNIX_PERMISSIONS_ATTRIBUTE,
#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE)







>
>
>
>







106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123

typedef int (TraversalProc) _ANSI_ARGS_((Tcl_DString *srcPtr,
	Tcl_DString *dstPtr, CONST Tcl_StatBuf *statBufPtr, int type,
	Tcl_DString *errorPtr));

/*
 * Constants and variables necessary for file attributes subcommand.
 * 
 * IMPORTANT: The permissions attribute is assumed to be the third
 * item (i.e. to be indexed with '2' in arrays) in code in tclIOUtil.c
 * and possibly elsewhere in Tcl's core.
 */

enum {
    UNIX_GROUP_ATTRIBUTE,
    UNIX_OWNER_ATTRIBUTE,
    UNIX_PERMISSIONS_ATTRIBUTE,
#if defined(HAVE_CHFLAGS) && defined(UF_IMMUTABLE)
467
468
469
470
471
472
473






474
475
476
477
478
479
480
481
482
483
484
485
{
    int srcFd;
    int dstFd;
    u_int blockSize;   /* Optimal I/O blocksize for filesystem */
    char *buffer;      /* Data buffer for copy */
    size_t nread;







    if ((srcFd = TclOSopen(src, O_RDONLY, 0)) < 0) {	/* INTL: Native. */
	return TCL_ERROR;
    }

    dstFd = TclOSopen(dst, O_CREAT|O_TRUNC|O_WRONLY,	/* INTL: Native. */
	    statBufPtr->st_mode);
    if (dstFd < 0) {
	close(srcFd); 
	return TCL_ERROR;
    }

#ifdef HAVE_ST_BLKSIZE







>
>
>
>
>
>
|



|







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
{
    int srcFd;
    int dstFd;
    u_int blockSize;   /* Optimal I/O blocksize for filesystem */
    char *buffer;      /* Data buffer for copy */
    size_t nread;

#ifdef DJGPP
#define BINMODE |O_BINARY
#else
#define BINMODE
#endif

    if ((srcFd = TclOSopen(src, O_RDONLY BINMODE, 0)) < 0) {	/* INTL: Native. */
	return TCL_ERROR;
    }

    dstFd = TclOSopen(dst, O_CREAT|O_TRUNC|O_WRONLY BINMODE,	/* INTL: Native. */
	    statBufPtr->st_mode);
    if (dstFd < 0) {
	close(srcFd); 
	return TCL_ERROR;
    }

#ifdef HAVE_ST_BLKSIZE
Changes to unix/tclUnixFile.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclUnixFile.c --
 *
 *      This file contains wrappers around UNIX file handling functions.
 *      These wrappers mask differences between Windows and UNIX.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclUnixFile.c,v 1.32.4.1 2003/10/16 02:28:03 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

static int NativeMatchType(CONST char* nativeName, Tcl_GlobTypeData *types);












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclUnixFile.c --
 *
 *      This file contains wrappers around UNIX file handling functions.
 *      These wrappers mask differences between Windows and UNIX.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclUnixFile.c,v 1.32.4.2 2004/02/07 05:48:09 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"

static int NativeMatchType(CONST char* nativeName, Tcl_GlobTypeData *types);

205
206
207
208
209
210
211





212
213
214
215
216
217
218
    CONST char *pattern;	/* Pattern to match against. */
    Tcl_GlobTypeData *types;	/* Object containing list of acceptable types.
				 * May be NULL. In particular the directory
				 * flag is very important. */
{
    CONST char *native;
    Tcl_Obj *fileNamePtr;






    fileNamePtr = Tcl_FSGetTranslatedPath(interp, pathPtr);
    if (fileNamePtr == NULL) {
	return TCL_ERROR;
    }
    
    if (pattern == NULL || (*pattern == '\0')) {







>
>
>
>
>







205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
    CONST char *pattern;	/* Pattern to match against. */
    Tcl_GlobTypeData *types;	/* Object containing list of acceptable types.
				 * May be NULL. In particular the directory
				 * flag is very important. */
{
    CONST char *native;
    Tcl_Obj *fileNamePtr;

    if (types != NULL && types->type == TCL_GLOB_TYPE_MOUNT) {
	/* The native filesystem never adds mounts */
	return TCL_OK;
    }

    fileNamePtr = Tcl_FSGetTranslatedPath(interp, pathPtr);
    if (fileNamePtr == NULL) {
	return TCL_ERROR;
    }
    
    if (pattern == NULL || (*pattern == '\0')) {
263
264
265
266
267
268
269

270
271
272
273
274
275
276

	native = Tcl_UtfToExternalDString(NULL, dirName, -1, &ds);

	if ((TclOSstat(native, &statBuf) != 0)		/* INTL: Native. */
		|| !S_ISDIR(statBuf.st_mode)) {
	    Tcl_DStringFree(&dsOrig);
	    Tcl_DStringFree(&ds);

	    return TCL_OK;
	}

	d = opendir(native);				/* INTL: Native. */
	if (d == NULL) {
	    Tcl_DStringFree(&ds);
	    Tcl_ResetResult(interp);







>







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

	native = Tcl_UtfToExternalDString(NULL, dirName, -1, &ds);

	if ((TclOSstat(native, &statBuf) != 0)		/* INTL: Native. */
		|| !S_ISDIR(statBuf.st_mode)) {
	    Tcl_DStringFree(&dsOrig);
	    Tcl_DStringFree(&ds);
	    Tcl_DecrRefCount(fileNamePtr);
	    return TCL_OK;
	}

	d = opendir(native);				/* INTL: Native. */
	if (d == NULL) {
	    Tcl_DStringFree(&ds);
	    Tcl_ResetResult(interp);
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
{
    return TclOSlstat(Tcl_FSGetNativePath(pathPtr), bufPtr);
}

/*
 *---------------------------------------------------------------------------
 *














































 * TclpObjGetCwd --
 *
 *	This function replaces the library version of getcwd().


 *
 * Results:
 *	The result is a pointer to a string specifying the current
 *	directory, or NULL if the current directory could not be
 *	determined.  If NULL is returned, an error message is left in the
 *	interp's result.  Storage for the result string is allocated in
 *	bufferPtr; the caller must call Tcl_DStringFree() when the result
 *	is no longer needed.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

Tcl_Obj* 
TclpObjGetCwd(interp)
    Tcl_Interp *interp;
{
    Tcl_DString ds;
    if (TclpGetCwd(interp, &ds) != NULL) {
	Tcl_Obj *cwdPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
	Tcl_IncrRefCount(cwdPtr);
	Tcl_DStringFree(&ds);
	return cwdPtr;
    } else {
	return NULL;
    }
}

/* Older string based version */
CONST char *
TclpGetCwd(interp, bufferPtr)
    Tcl_Interp *interp;		/* If non-NULL, used for error reporting. */
    Tcl_DString *bufferPtr;	/* Uninitialized or free DString filled
				 * with name of current directory. */
{
    char buffer[MAXPATHLEN+1];







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


>
>
|














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







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
{
    return TclOSlstat(Tcl_FSGetNativePath(pathPtr), bufPtr);
}

/*
 *---------------------------------------------------------------------------
 *
 * TclpGetNativeCwd --
 *
 *	This function replaces the library version of getcwd().
 *
 * Results:
 *	The input and output are filesystem paths in native form.  The
 *	result is either the given clientData, if the working directory
 *	hasn't changed, or a new clientData (owned by our caller),
 *	giving the new native path, or NULL if the current directory
 *	could not be determined.  If NULL is returned, the caller can
 *	examine the standard posix error codes to determine the cause of
 *	the problem.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

ClientData
TclpGetNativeCwd(clientData)
    ClientData clientData;
{
    char buffer[MAXPATHLEN+1];

#ifdef USEGETWD
    if (getwd(buffer) == NULL) {			/* INTL: Native. */
#else
    if (getcwd(buffer, MAXPATHLEN + 1) == NULL) {	/* INTL: Native. */
#endif
	return NULL;
    }
    if ((clientData != NULL) && strcmp(buffer, (CONST char*)clientData) == 0) {
	/* No change to pwd */
	return clientData;
    } else {
	char *newCd = (char *) ckalloc((unsigned) 
				       (strlen(buffer) + 1));
	strcpy(newCd, buffer);
	return (ClientData) newCd;
    }
}

/*
 *---------------------------------------------------------------------------
 *
 * TclpGetCwd --
 *
 *	This function replaces the library version of getcwd().
 *      (Obsolete function, only retained for old extensions which
 *      may call it directly).
 *      
 * Results:
 *	The result is a pointer to a string specifying the current
 *	directory, or NULL if the current directory could not be
 *	determined.  If NULL is returned, an error message is left in the
 *	interp's result.  Storage for the result string is allocated in
 *	bufferPtr; the caller must call Tcl_DStringFree() when the result
 *	is no longer needed.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

















CONST char *
TclpGetCwd(interp, bufferPtr)
    Tcl_Interp *interp;		/* If non-NULL, used for error reporting. */
    Tcl_DString *bufferPtr;	/* Uninitialized or free DString filled
				 * with name of current directory. */
{
    char buffer[MAXPATHLEN+1];
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
TclpObjLink(pathPtr, toPtr, linkAction)
    Tcl_Obj *pathPtr;
    Tcl_Obj *toPtr;
    int linkAction;
{
    if (toPtr != NULL) {
	CONST char *src = Tcl_FSGetNativePath(pathPtr);



































	CONST char *target = Tcl_FSGetNativePath(toPtr);




	
	if (src == NULL || target == NULL) {
	    return NULL;
	}


	if (access(src, F_OK) != -1) {
	    /* src exists */
	    errno = EEXIST;
	    return NULL;
	}
	if (access(target, F_OK) == -1) {
	    /* target doesn't exist */
	    errno = ENOENT;
	    return NULL;
	}
	/* 
	 * Check symbolic link flag first, since we prefer to
	 * create these.
	 */
	if (linkAction & TCL_CREATE_SYMBOLIC_LINK) {
















	    if (symlink(target, src) != 0) return NULL;



	} else if (linkAction & TCL_CREATE_HARD_LINK) {
	    if (link(target, src) != 0) return NULL;


	} else {
	    errno = ENODEV;
	    return NULL;
	}
	return toPtr;
    } else {
	Tcl_Obj* linkPtr = NULL;







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





<
<
<
<
<





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

|
>
>







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
TclpObjLink(pathPtr, toPtr, linkAction)
    Tcl_Obj *pathPtr;
    Tcl_Obj *toPtr;
    int linkAction;
{
    if (toPtr != NULL) {
	CONST char *src = Tcl_FSGetNativePath(pathPtr);
	CONST char *target = NULL;
	if (src == NULL) return NULL;
	
	/* 
	 * If we're making a symbolic link and the path is relative,
	 * then we must check whether it exists _relative_ to the
	 * directory in which the src is found (not relative to the
	 * current cwd which is just not relevant in this case).
	 * 
	 * If we're making a hard link, then a relative path is
	 * just converted to absolute relative to the cwd.
	 */
	if ((linkAction & TCL_CREATE_SYMBOLIC_LINK)
	  && (Tcl_FSGetPathType(toPtr) == TCL_PATH_RELATIVE)) {
	    Tcl_Obj *dirPtr, *absPtr;
	    dirPtr = TclPathPart(NULL, pathPtr, TCL_PATH_DIRNAME);
	    if (dirPtr == NULL) {
	        return NULL;
	    }
	    absPtr = Tcl_FSJoinToPath(dirPtr, 1, &toPtr);
	    Tcl_IncrRefCount(absPtr);
	    if (Tcl_FSAccess(absPtr, F_OK) == -1) {
		Tcl_DecrRefCount(absPtr);
		Tcl_DecrRefCount(dirPtr);
		/* target doesn't exist */
		errno = ENOENT;
	        return NULL;
	    }
	    /* 
	     * Target exists; we'll construct the relative
	     * path we want below.
	     */
	    Tcl_DecrRefCount(absPtr);
	    Tcl_DecrRefCount(dirPtr);
	} else {
	    target = Tcl_FSGetNativePath(toPtr);
	    if (access(target, F_OK) == -1) {
		/* target doesn't exist */
		errno = ENOENT;
		return NULL;
	    }
	    if (target == NULL) {
		return NULL;
	    }
	}
	
	if (access(src, F_OK) != -1) {
	    /* src exists */
	    errno = EEXIST;
	    return NULL;
	}





	/* 
	 * Check symbolic link flag first, since we prefer to
	 * create these.
	 */
	if (linkAction & TCL_CREATE_SYMBOLIC_LINK) {
	    int targetLen;
	    Tcl_DString ds;
	    Tcl_Obj *transPtr;
	    /* 
	     * Now we don't want to link to the absolute, normalized path.
	     * Relative links are quite acceptable (but links to ~user
	     * are not -- these must be expanded first).
	     */
	    transPtr = Tcl_FSGetTranslatedPath(NULL, toPtr);
	    if (transPtr == NULL) {
		return NULL;
	    }
	    target = Tcl_GetStringFromObj(transPtr, &targetLen);
	    target = Tcl_UtfToExternalDString(NULL, target, targetLen, &ds);
	    Tcl_DecrRefCount(transPtr);
	    
	    if (symlink(target, src) != 0) {
	        toPtr = NULL;
	    }
	    Tcl_DStringFree(&ds);
	} else if (linkAction & TCL_CREATE_HARD_LINK) {
	    if (link(target, src) != 0) {
		return NULL;
	    }
	} else {
	    errno = ENODEV;
	    return NULL;
	}
	return toPtr;
    } else {
	Tcl_Obj* linkPtr = NULL;
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj*
TclpFilesystemPathType(pathObjPtr)
    Tcl_Obj* pathObjPtr;
{
    /* All native paths are of the same type */
    return NULL;
}

/*
 *---------------------------------------------------------------------------







|
|







885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj*
TclpFilesystemPathType(pathPtr)
    Tcl_Obj* pathPtr;
{
    /* All native paths are of the same type */
    return NULL;
}

/*
 *---------------------------------------------------------------------------
Changes to unix/tclUnixInit.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* 
 * tclUnixInit.c --
 *
 *	Contains the Unix-specific interpreter initialization functions.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 * Copyright (c) 1999 by Scriptics Corporation.
 * All rights reserved.
 *
 * RCS: @(#) $Id: tclUnixInit.c,v 1.35 2003/05/13 08:40:31 das Exp $
 */

#if defined(HAVE_CFBUNDLE)
#include <CoreFoundation/CoreFoundation.h>
#endif
#include "tclInt.h"
#include "tclPort.h"









|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* 
 * tclUnixInit.c --
 *
 *	Contains the Unix-specific interpreter initialization functions.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 * Copyright (c) 1999 by Scriptics Corporation.
 * All rights reserved.
 *
 * RCS: @(#) $Id: tclUnixInit.c,v 1.35.2.1 2004/02/07 05:48:10 dgp Exp $
 */

#if defined(HAVE_CFBUNDLE)
#include <CoreFoundation/CoreFoundation.h>
#endif
#include "tclInt.h"
#include "tclPort.h"
163
164
165
166
167
168
169



170

171
172
173
174
175
176
177
 *
 *---------------------------------------------------------------------------
 */

void
TclpInitPlatform()
{



    tclPlatform = TCL_PLATFORM_UNIX;


    /*
     * The code below causes SIGPIPE (broken pipe) errors to
     * be ignored.  This is needed so that Tcl processes don't
     * die if they create child processes (e.g. using "exec" or
     * "open") that terminate prematurely.  The signal handler
     * is only set up when the first interpreter is created;







>
>
>

>







163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
 *
 *---------------------------------------------------------------------------
 */

void
TclpInitPlatform()
{
#ifdef DJGPP
    tclPlatform = TCL_PLATFORM_WINDOWS;
#else		
    tclPlatform = TCL_PLATFORM_UNIX;
#endif

    /*
     * The code below causes SIGPIPE (broken pipe) errors to
     * be ignored.  This is needed so that Tcl processes don't
     * die if they create child processes (e.g. using "exec" or
     * "open") that terminate prematurely.  The signal handler
     * is only set up when the first interpreter is created;
334
335
336
337
338
339
340



341















342
343
344
345
346
347
348

     /*
      * The variable path holds an absolute path.  Take care not to
      * overwrite pathv[0] since that might produce a relative path.
      */

    if (path != NULL) {



	Tcl_SplitPath(path, &pathc, &pathv);















	if (pathc > 2) {
	    str = pathv[pathc - 2];
	    pathv[pathc - 2] = installLib;
	    path = Tcl_JoinPath(pathc - 1, pathv, &ds);
	    pathv[pathc - 2] = str;
	    objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
	    Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);







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







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

     /*
      * The variable path holds an absolute path.  Take care not to
      * overwrite pathv[0] since that might produce a relative path.
      */

    if (path != NULL) {
	int i, origc;
	CONST char **origv;

	Tcl_SplitPath(path, &origc, &origv);
	pathc = 0;
	pathv = (CONST char **) ckalloc((unsigned int)(origc * sizeof(char *)));
	for (i=0; i< origc; i++) {
	    if (origv[i][0] == '.') {
		if (strcmp(origv[i], ".") == 0) {
		    /* do nothing */
		} else if (strcmp(origv[i], "..") == 0) {
		    pathc--;
		} else {
		    pathv[pathc++] = origv[i];
		}
	    } else {
		pathv[pathc++] = origv[i];
	    }
	}
	if (pathc > 2) {
	    str = pathv[pathc - 2];
	    pathv[pathc - 2] = installLib;
	    path = Tcl_JoinPath(pathc - 1, pathv, &ds);
	    pathv[pathc - 2] = str;
	    objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
	    Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
389
390
391
392
393
394
395

396
397
398
399
400
401
402
	    pathv[pathc - 4] = developLib;
	    path = Tcl_JoinPath(pathc - 3, pathv, &ds);
	    pathv[pathc - 4] = str;
	    objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
	    Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
	    Tcl_DStringFree(&ds);
	}

	ckfree((char *) pathv);
    }

    /*
     * Finally, look for the library relative to the compiled-in path.
     * This is needed when users install Tcl with an exec-prefix that
     * is different from the prtefix.







>







411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
	    pathv[pathc - 4] = developLib;
	    path = Tcl_JoinPath(pathc - 3, pathv, &ds);
	    pathv[pathc - 4] = str;
	    objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
	    Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
	    Tcl_DStringFree(&ds);
	}
	ckfree((char *) origv);
	ckfree((char *) pathv);
    }

    /*
     * Finally, look for the library relative to the compiled-in path.
     * This is needed when users install Tcl with an exec-prefix that
     * is different from the prtefix.
Changes to unix/tclUnixNotfy.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * tclUnixNotify.c --
 *
 *	This file contains the implementation of the select-based
 *	Unix-specific notifier, which is the lowest-level part of the
 *	Tcl event loop.  This file works together with
 *	../generic/tclNotify.c.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclUnixNotfy.c,v 1.12.2.1 2003/08/07 21:36:05 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include <signal.h> 

extern TclStubs tclStubs;













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * tclUnixNotify.c --
 *
 *	This file contains the implementation of the select-based
 *	Unix-specific notifier, which is the lowest-level part of the
 *	Tcl event loop.  This file works together with
 *	../generic/tclNotify.c.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclUnixNotfy.c,v 1.12.2.2 2004/02/07 05:48:11 dgp Exp $
 */

#include "tclInt.h"
#include "tclPort.h"
#include <signal.h> 

extern TclStubs tclStubs;
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
     * Start the Notifier thread if necessary.
     */

    Tcl_MutexLock(&notifierMutex);
    if (notifierCount == 0) {
	if (Tcl_CreateThread(&notifierThread, NotifierThreadProc, NULL,
		     TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS) != TCL_OK) {
	    panic("Tcl_InitNotifier: unable to start notifier thread");
	}
    }
    notifierCount++;

    /*
     * Wait for the notifier pipe to be created.
     */







|







206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
     * Start the Notifier thread if necessary.
     */

    Tcl_MutexLock(&notifierMutex);
    if (notifierCount == 0) {
	if (Tcl_CreateThread(&notifierThread, NotifierThreadProc, NULL,
		     TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS) != TCL_OK) {
	    Tcl_Panic("Tcl_InitNotifier: unable to start notifier thread");
	}
    }
    notifierCount++;

    /*
     * Wait for the notifier pipe to be created.
     */
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
    /*
     * If this is the last thread to use the notifier, close the notifier
     * pipe and wait for the background thread to terminate.
     */

    if (notifierCount == 0) {
	if (triggerPipe < 0) {
	    panic("Tcl_FinalizeNotifier: notifier pipe not initialized");
	}

        /*
	 * Send "q" message to the notifier thread so that it will
	 * terminate.  The notifier will return from its call to select()
	 * and notice that a "q" message has arrived, it will then close
	 * its side of the pipe and terminate its thread.  Note the we can







|







259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
    /*
     * If this is the last thread to use the notifier, close the notifier
     * pipe and wait for the background thread to terminate.
     */

    if (notifierCount == 0) {
	if (triggerPipe < 0) {
	    Tcl_Panic("Tcl_FinalizeNotifier: notifier pipe not initialized");
	}

        /*
	 * Send "q" message to the notifier thread so that it will
	 * terminate.  The notifier will return from its call to select()
	 * and notice that a "q" message has arrived, it will then close
	 * its side of the pipe and terminate its thread.  Note the we can
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
    int i, status, index, bit, numFdBits, receivePipe;
    long found, word;
    struct timeval poll = {0., 0.}, *timePtr;
    int maskSize = 3 * ((MASK_SIZE) / sizeof(long)) * sizeof(fd_mask);
    char buf[2];

    if (pipe(fds) != 0) {
	panic("NotifierThreadProc: could not create trigger pipe.");
    }

    receivePipe = fds[0];

#ifndef USE_FIONBIO
    status = fcntl(receivePipe, F_GETFL);
    status |= O_NONBLOCK;
    if (fcntl(receivePipe, F_SETFL, status) < 0) {
	panic("NotifierThreadProc: could not make receive pipe non blocking.");
    }
    status = fcntl(fds[1], F_GETFL);
    status |= O_NONBLOCK;
    if (fcntl(fds[1], F_SETFL, status) < 0) {
	panic("NotifierThreadProc: could not make trigger pipe non blocking.");
    }
#else
    if (ioctl(receivePipe, (int) FIONBIO, &status) < 0) {
	panic("NotifierThreadProc: could not make receive pipe non blocking.");
    }
    if (ioctl(fds[1], (int) FIONBIO, &status) < 0) {
	panic("NotifierThreadProc: could not make trigger pipe non blocking.");
    }
#endif

    /*
     * Install the write end of the pipe into the global variable.
     */








|








|




|



|


|







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
    int i, status, index, bit, numFdBits, receivePipe;
    long found, word;
    struct timeval poll = {0., 0.}, *timePtr;
    int maskSize = 3 * ((MASK_SIZE) / sizeof(long)) * sizeof(fd_mask);
    char buf[2];

    if (pipe(fds) != 0) {
	Tcl_Panic("NotifierThreadProc: could not create trigger pipe.");
    }

    receivePipe = fds[0];

#ifndef USE_FIONBIO
    status = fcntl(receivePipe, F_GETFL);
    status |= O_NONBLOCK;
    if (fcntl(receivePipe, F_SETFL, status) < 0) {
	Tcl_Panic("NotifierThreadProc: could not make receive pipe non blocking.");
    }
    status = fcntl(fds[1], F_GETFL);
    status |= O_NONBLOCK;
    if (fcntl(fds[1], F_SETFL, status) < 0) {
	Tcl_Panic("NotifierThreadProc: could not make trigger pipe non blocking.");
    }
#else
    if (ioctl(receivePipe, (int) FIONBIO, &status) < 0) {
	Tcl_Panic("NotifierThreadProc: could not make receive pipe non blocking.");
    }
    if (ioctl(fds[1], (int) FIONBIO, &status) < 0) {
	Tcl_Panic("NotifierThreadProc: could not make trigger pipe non blocking.");
    }
#endif

    /*
     * Install the write end of the pipe into the global variable.
     */

Changes to unix/tclUnixPort.h.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 *
 * Copyright (c) 1991-1994 The Regents of the University of California.
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclUnixPort.h,v 1.28.2.1 2003/06/24 17:27:41 dgp Exp $
 */

#ifndef _TCLUNIXPORT
#define _TCLUNIXPORT

#ifndef _TCLINT
#   include "tclInt.h"







|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 *
 * Copyright (c) 1991-1994 The Regents of the University of California.
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclUnixPort.h,v 1.28.2.2 2004/02/07 05:48:11 dgp Exp $
 */

#ifndef _TCLUNIXPORT
#define _TCLUNIXPORT

#ifndef _TCLINT
#   include "tclInt.h"
460
461
462
463
464
465
466

467

468
469
470
471
472
473
474

/*
 * Not all systems declare the errno variable in errno.h. so this
 * file does it explicitly.  The list of system error messages also
 * isn't generally declared in a header file anywhere.
 */


extern int errno;


/*
 * Not all systems declare all the errors that Tcl uses!  Provide some
 * work-arounds...
 */

#ifndef EOVERFLOW







>

>







460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476

/*
 * Not all systems declare the errno variable in errno.h. so this
 * file does it explicitly.  The list of system error messages also
 * isn't generally declared in a header file anywhere.
 */

#ifdef NO_ERRNO
extern int errno;
#endif /* NO_ERRNO */

/*
 * Not all systems declare all the errors that Tcl uses!  Provide some
 * work-arounds...
 */

#ifndef EOVERFLOW
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

/*
 * The default platform eol translation on Unix is TCL_TRANSLATE_LF.
 */

#ifdef DJGPP
#define	TCL_PLATFORM_TRANSLATION	TCL_TRANSLATE_CRLF

#else
#define	TCL_PLATFORM_TRANSLATION	TCL_TRANSLATE_LF
#endif

/*
 * The following macros have trivial definitions, allowing generic code to 
 * address platform-specific issues.
 */

#define TclpGetPid(pid)		((unsigned long) (pid))
#define TclpReleaseFile(file)	/* Nothing. */

/*
 * The following defines wrap the system memory allocation routines for
 * use by tclAlloc.c.  By default off unused on Unix.
 */

#if USE_TCLALLOC
#   define TclpSysAlloc(size, isBin)	malloc((size_t)size)
#   define TclpSysFree(ptr)		free((char*)ptr)
#   define TclpSysRealloc(ptr, size)	realloc((char*)ptr, (size_t)size)
#endif

/*
 * The following macros and declaration wrap the C runtime library
 * functions.
 */

#define TclpExit		exit







>













|
<


<
|
|
|
<







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

/*
 * The default platform eol translation on Unix is TCL_TRANSLATE_LF.
 */

#ifdef DJGPP
#define	TCL_PLATFORM_TRANSLATION	TCL_TRANSLATE_CRLF
typedef int socklen_t;
#else
#define	TCL_PLATFORM_TRANSLATION	TCL_TRANSLATE_LF
#endif

/*
 * The following macros have trivial definitions, allowing generic code to 
 * address platform-specific issues.
 */

#define TclpGetPid(pid)		((unsigned long) (pid))
#define TclpReleaseFile(file)	/* Nothing. */

/*
 * The following defines wrap the system memory allocation routines.

 */


#define TclpSysAlloc(size, isBin)	malloc((size_t)size)
#define TclpSysFree(ptr)		free((char*)ptr)
#define TclpSysRealloc(ptr, size)	realloc((char*)ptr, (size_t)size)


/*
 * The following macros and declaration wrap the C runtime library
 * functions.
 */

#define TclpExit		exit
Changes to unix/tclUnixThrd.c.
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
    struct lock {
        Tcl_Mutex       tlock;
        pthread_mutex_t plock;
    } *lockPtr;

    lockPtr = malloc(sizeof(struct lock));
    if (lockPtr == NULL) {
	panic("could not allocate lock");
    }
    lockPtr->tlock = (Tcl_Mutex) &lockPtr->plock;
    pthread_mutex_init(&lockPtr->plock, NULL);
    return &lockPtr->tlock;
}

static void







|







912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
    struct lock {
        Tcl_Mutex       tlock;
        pthread_mutex_t plock;
    } *lockPtr;

    lockPtr = malloc(sizeof(struct lock));
    if (lockPtr == NULL) {
	Tcl_Panic("could not allocate lock");
    }
    lockPtr->tlock = (Tcl_Mutex) &lockPtr->plock;
    pthread_mutex_init(&lockPtr->plock, NULL);
    return &lockPtr->tlock;
}

static void
Changes to unix/tclXtNotify.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclXtNotify.c --
 *
 *	This file contains the notifier driver implementation for the
 *	Xt intrinsics.
 *
 * Copyright (c) 1997 by Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclXtNotify.c,v 1.4 1999/07/02 06:05:34 welch Exp $
 */

#include <X11/Intrinsic.h>
#include <tclInt.h>

/*
 * This structure is used to keep track of the notifier info for a 











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclXtNotify.c --
 *
 *	This file contains the notifier driver implementation for the
 *	Xt intrinsics.
 *
 * Copyright (c) 1997 by Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclXtNotify.c,v 1.4.34.1 2004/02/07 05:48:11 dgp Exp $
 */

#include <X11/Intrinsic.h>
#include <tclInt.h>

/*
 * This structure is used to keep track of the notifier info for a 
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
        if (appContext != NULL) {

	    /*
             * We already have a context. We do not allow switching contexts
             * after initialization, so we panic.
             */
        
            panic("TclSetAppContext:  multiple application contexts");

        }
    } else {

        /*
         * If we get here we have not yet gotten a context, so either create
         * one or use the one supplied by our caller.







|







131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
        if (appContext != NULL) {

	    /*
             * We already have a context. We do not allow switching contexts
             * after initialization, so we panic.
             */
        
            Tcl_Panic("TclSetAppContext:  multiple application contexts");

        }
    } else {

        /*
         * If we get here we have not yet gotten a context, so either create
         * one or use the one supplied by our caller.
Changes to win/Makefile.in.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#
# This file is a Makefile for Tcl.  If it has the name "Makefile.in"
# then it is a template for a Makefile;  to generate the actual Makefile,
# run "./configure", which is a configuration script generated by the
# "autoconf" program (constructs like "@foo@" will get replaced in the
# actual Makefile.
#
# RCS: @(#) $Id: Makefile.in,v 1.71.2.2 2003/06/27 15:10:12 dgp Exp $

VERSION = @TCL_VERSION@

#----------------------------------------------------------------
# Things you can change to personalize the Makefile for your own
# site (you can make these changes in either Makefile.in or
# Makefile, but changes to Makefile will get lost if you re-run







|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#
# This file is a Makefile for Tcl.  If it has the name "Makefile.in"
# then it is a template for a Makefile;  to generate the actual Makefile,
# run "./configure", which is a configuration script generated by the
# "autoconf" program (constructs like "@foo@" will get replaced in the
# actual Makefile.
#
# RCS: @(#) $Id: Makefile.in,v 1.71.2.3 2004/02/07 05:48:11 dgp Exp $

VERSION = @TCL_VERSION@

#----------------------------------------------------------------
# Things you can change to personalize the Makefile for your own
# site (you can make these changes in either Makefile.in or
# Makefile, but changes to Makefile will get lost if you re-run
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
	    if [ ! -d $$i ] ; then \
		echo "Making directory $$i"; \
		$(MKDIR) $$i; \
		chmod 755 $$i; \
		else true; \
		fi; \
	    done;
	@for i in dde1.2 reg1.1; \
	    do \
	    if [ ! -d $(LIB_INSTALL_DIR)/$$i ] ; then \
		echo "Making directory $(LIB_INSTALL_DIR)/$$i"; \
		$(MKDIR) $(LIB_INSTALL_DIR)/$$i; \
		else true; \
		fi; \
	    done;







|







464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
	    if [ ! -d $$i ] ; then \
		echo "Making directory $$i"; \
		$(MKDIR) $$i; \
		chmod 755 $$i; \
		else true; \
		fi; \
	    done;
	@for i in dde1.3 reg1.1; \
	    do \
	    if [ ! -d $(LIB_INSTALL_DIR)/$$i ] ; then \
		echo "Making directory $(LIB_INSTALL_DIR)/$$i"; \
		$(MKDIR) $(LIB_INSTALL_DIR)/$$i; \
		else true; \
		fi; \
	    done;
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
	    if [ -f $$i ]; then \
		echo "Installing $$i to $(LIB_INSTALL_DIR)/"; \
		$(COPY) $$i "$(LIB_INSTALL_DIR)"; \
	    fi; \
	    done
	@if [ -f $(DDE_DLL_FILE) ]; then \
	    echo installing $(DDE_DLL_FILE); \
	    $(COPY) $(DDE_DLL_FILE) $(LIB_INSTALL_DIR)/dde1.2; \
	    $(COPY) $(ROOT_DIR)/library/dde/pkgIndex.tcl \
		$(LIB_INSTALL_DIR)/dde1.2; \
	    fi
	@if [ -f $(DDE_LIB_FILE) ]; then \
	    echo installing $(DDE_LIB_FILE); \
	    $(COPY) $(DDE_LIB_FILE) $(LIB_INSTALL_DIR)/dde1.2; \
	    fi
	@if [ -f $(REG_DLL_FILE) ]; then \
	    echo installing $(REG_DLL_FILE); \
	    $(COPY) $(REG_DLL_FILE) $(LIB_INSTALL_DIR)/reg1.1; \
	    $(COPY) $(ROOT_DIR)/library/reg/pkgIndex.tcl \
		$(LIB_INSTALL_DIR)/reg1.1; \
	    fi







|

|



|







488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
	    if [ -f $$i ]; then \
		echo "Installing $$i to $(LIB_INSTALL_DIR)/"; \
		$(COPY) $$i "$(LIB_INSTALL_DIR)"; \
	    fi; \
	    done
	@if [ -f $(DDE_DLL_FILE) ]; then \
	    echo installing $(DDE_DLL_FILE); \
	    $(COPY) $(DDE_DLL_FILE) $(LIB_INSTALL_DIR)/dde1.3; \
	    $(COPY) $(ROOT_DIR)/library/dde/pkgIndex.tcl \
		$(LIB_INSTALL_DIR)/dde1.3; \
	    fi
	@if [ -f $(DDE_LIB_FILE) ]; then \
	    echo installing $(DDE_LIB_FILE); \
	    $(COPY) $(DDE_LIB_FILE) $(LIB_INSTALL_DIR)/dde1.3; \
	    fi
	@if [ -f $(REG_DLL_FILE) ]; then \
	    echo installing $(REG_DLL_FILE); \
	    $(COPY) $(REG_DLL_FILE) $(LIB_INSTALL_DIR)/reg1.1; \
	    $(COPY) $(ROOT_DIR)/library/reg/pkgIndex.tcl \
		$(LIB_INSTALL_DIR)/reg1.1; \
	    fi
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
	    do \
	    if [ ! -d $$i ] ; then \
		echo "Making directory $$i"; \
		$(MKDIR) $$i; \
		else true; \
		fi; \
	    done;
	@for i in http1.0 http2.4 opt0.4 encoding msgcat1.3 tcltest2.2; \
	    do \
	    if [ ! -d $(SCRIPT_INSTALL_DIR)/$$i ] ; then \
		echo "Making directory $(SCRIPT_INSTALL_DIR)/$$i"; \
		$(MKDIR) $(SCRIPT_INSTALL_DIR)/$$i; \
		else true; \
		fi; \
	    done;







|







517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
	    do \
	    if [ ! -d $$i ] ; then \
		echo "Making directory $$i"; \
		$(MKDIR) $$i; \
		else true; \
		fi; \
	    done;
	@for i in http1.0 http2.4 opt0.4 encoding msgcat1.4 tcltest2.2; \
	    do \
	    if [ ! -d $(SCRIPT_INSTALL_DIR)/$$i ] ; then \
		echo "Making directory $(SCRIPT_INSTALL_DIR)/$$i"; \
		$(MKDIR) $(SCRIPT_INSTALL_DIR)/$$i; \
		else true; \
		fi; \
	    done;
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
	    $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/http2.4"; \
	    done;
	@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 library msgcat1.3 directory";
	@for j in $(ROOT_DIR)/library/msgcat/*.tcl; \
	    do \
	    $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/msgcat1.3"; \
	    done;
	@echo "Installing library tcltest2.2 directory";
	@for j in $(ROOT_DIR)/library/tcltest/*.tcl; \
	    do \
	    $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/tcltest2.2"; \
	    done;
	@echo "Installing encodings";







|


|







551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
	    $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/http2.4"; \
	    done;
	@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 library msgcat1.4 directory";
	@for j in $(ROOT_DIR)/library/msgcat/*.tcl; \
	    do \
	    $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/msgcat1.4"; \
	    done;
	@echo "Installing library tcltest2.2 directory";
	@for j in $(ROOT_DIR)/library/tcltest/*.tcl; \
	    do \
	    $(COPY) "$$j" "$(SCRIPT_INSTALL_DIR)/tcltest2.2"; \
	    done;
	@echo "Installing encodings";
Changes to win/configure.
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289

TCL_VERSION=8.5
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=5
TCL_PATCH_LEVEL="a0"
VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION

TCL_DDE_VERSION=1.2
TCL_DDE_MAJOR_VERSION=1
TCL_DDE_MINOR_VERSION=2
TCL_DDE_PATCH_LEVEL=""
DDEVER=$TCL_DDE_MAJOR_VERSION$TCL_DDE_MINOR_VERSION

TCL_REG_VERSION=1.1
TCL_REG_MAJOR_VERSION=1
TCL_REG_MINOR_VERSION=1
TCL_REG_PATCH_LEVEL=""







|

|







1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289

TCL_VERSION=8.5
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=5
TCL_PATCH_LEVEL="a0"
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=""
DDEVER=$TCL_DDE_MAJOR_VERSION$TCL_DDE_MINOR_VERSION

TCL_REG_VERSION=1.1
TCL_REG_MAJOR_VERSION=1
TCL_REG_MINOR_VERSION=1
TCL_REG_PATCH_LEVEL=""
Changes to win/configure.in.
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
#! /bin/bash -norc
# This file is an input file used by the GNU "autoconf" program to
# generate the file "configure", which is run during Tcl installation
# to configure the system for the local environment.
#
# RCS: @(#) $Id: configure.in,v 1.74.2.1 2003/06/18 19:48:04 dgp Exp $

AC_INIT(../generic/tcl.h)
AC_PREREQ(2.57)

# The following define is needed when building with Cygwin since newer
# 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.5
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=5
TCL_PATCH_LEVEL="a0"
VER=$TCL_MAJOR_VERSION$TCL_MINOR_VERSION

TCL_DDE_VERSION=1.2
TCL_DDE_MAJOR_VERSION=1
TCL_DDE_MINOR_VERSION=2
TCL_DDE_PATCH_LEVEL=""
DDEVER=$TCL_DDE_MAJOR_VERSION$TCL_DDE_MINOR_VERSION

TCL_REG_VERSION=1.1
TCL_REG_MAJOR_VERSION=1
TCL_REG_MINOR_VERSION=1
TCL_REG_PATCH_LEVEL=""





|















|

|







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
#! /bin/bash -norc
# This file is an input file used by the GNU "autoconf" program to
# generate the file "configure", which is run during Tcl installation
# to configure the system for the local environment.
#
# RCS: @(#) $Id: configure.in,v 1.74.2.2 2004/02/07 05:48:12 dgp Exp $

AC_INIT(../generic/tcl.h)
AC_PREREQ(2.57)

# The following define is needed when building with Cygwin since newer
# 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.5
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=5
TCL_PATCH_LEVEL="a0"
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=""
DDEVER=$TCL_DDE_MAJOR_VERSION$TCL_DDE_MINOR_VERSION

TCL_REG_VERSION=1.1
TCL_REG_MAJOR_VERSION=1
TCL_REG_MINOR_VERSION=1
TCL_REG_PATCH_LEVEL=""
Changes to win/makefile.bc.
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
######################################################################

NAMEPREFIX	= tcl
STUBPREFIX	= $(NAMEPREFIX)stub
DOTVERSION	= 8.5
VERSION		= 85

DDEVERSION = 12
DDEDOTVERSION = 1.2

REGVERSION = 11
REGDOTVERSION = 1.1

BINROOT		= ..
!IF "$(NODEBUG)" == "1"
TMPDIRNAME	= Release







|
|







123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
######################################################################

NAMEPREFIX	= tcl
STUBPREFIX	= $(NAMEPREFIX)stub
DOTVERSION	= 8.5
VERSION		= 85

DDEVERSION = 13
DDEDOTVERSION = 1.3

REGVERSION = 11
REGDOTVERSION = 1.1

BINROOT		= ..
!IF "$(NODEBUG)" == "1"
TMPDIRNAME	= Release
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
	-@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\http2.4"
	-@copy "$(ROOT)\library\http\http.tcl"     "$(SCRIPT_INSTALL_DIR)\http2.4"
	-@copy "$(ROOT)\library\http\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\http2.4"
	@echo installing opt0.4
	-@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\opt0.4"
	-@copy "$(ROOT)\library\opt\optparse.tcl" "$(SCRIPT_INSTALL_DIR)\opt0.4"
	-@copy "$(ROOT)\library\opt\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\opt0.4"
	@echo installing msgcat1.3
	-@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\msgcat1.3"
	-@copy "$(ROOT)\library\msgcat\msgcat.tcl"   "$(SCRIPT_INSTALL_DIR)\msgcat1.3"
	-@copy "$(ROOT)\library\msgcat\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\msgcat1.3"
	@echo installing tcltest2.2
	-@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\tcltest2.2"
	-@copy "$(ROOT)\library\tcltest\tcltest.tcl"   "$(SCRIPT_INSTALL_DIR)\tcltest2.2"
	-@copy "$(ROOT)\library\tcltest\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\tcltest2.2"
	@echo installing $(TCLDDEDLLNAME)
	-@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\dde1.1"
	-@copy "$(TCLDDEDLL)" "$(SCRIPT_INSTALL_DIR)\dde1.1"
	-@copy "$(ROOT)\library\dde\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\dde1.1"
	@echo installing $(TCLREGDLLNAME)
	-@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\reg1.1"
	-@copy "$(TCLREGDLL)" "$(SCRIPT_INSTALL_DIR)\reg1.1"
	-@copy "$(ROOT)\library\reg\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\reg1.1"
	@echo installing encoding files
	-@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\encoding"
	-@copy "$(ROOT)\library\encoding\*.enc" "$(SCRIPT_INSTALL_DIR)\encoding"







|
|
|
|





|
|
|







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
	-@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\http2.4"
	-@copy "$(ROOT)\library\http\http.tcl"     "$(SCRIPT_INSTALL_DIR)\http2.4"
	-@copy "$(ROOT)\library\http\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\http2.4"
	@echo installing opt0.4
	-@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\opt0.4"
	-@copy "$(ROOT)\library\opt\optparse.tcl" "$(SCRIPT_INSTALL_DIR)\opt0.4"
	-@copy "$(ROOT)\library\opt\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\opt0.4"
	@echo installing msgcat1.4
	-@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\msgcat1.4"
	-@copy "$(ROOT)\library\msgcat\msgcat.tcl"   "$(SCRIPT_INSTALL_DIR)\msgcat1.4"
	-@copy "$(ROOT)\library\msgcat\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\msgcat1.4"
	@echo installing tcltest2.2
	-@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\tcltest2.2"
	-@copy "$(ROOT)\library\tcltest\tcltest.tcl"   "$(SCRIPT_INSTALL_DIR)\tcltest2.2"
	-@copy "$(ROOT)\library\tcltest\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\tcltest2.2"
	@echo installing $(TCLDDEDLLNAME)
	-@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\dde1.3"
	-@copy "$(TCLDDEDLL)" "$(SCRIPT_INSTALL_DIR)\dde1.3"
	-@copy "$(ROOT)\library\dde\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\dde1.3"
	@echo installing $(TCLREGDLLNAME)
	-@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\reg1.1"
	-@copy "$(TCLREGDLL)" "$(SCRIPT_INSTALL_DIR)\reg1.1"
	-@copy "$(ROOT)\library\reg\pkgIndex.tcl" "$(SCRIPT_INSTALL_DIR)\reg1.1"
	@echo installing encoding files
	-@$(MKDIR) "$(SCRIPT_INSTALL_DIR)\encoding"
	-@copy "$(ROOT)\library\encoding\*.enc" "$(SCRIPT_INSTALL_DIR)\encoding"
Changes to win/makefile.vc.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#------------------------------------------------------------------------------
# makefile.vc --
#
#	Microsoft Visual C++ makefile for use with nmake.exe v1.62+ (VC++ 5.0+)
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# Copyright (c) 1995-1996 Sun Microsystems, Inc.
# Copyright (c) 1998-2000 Ajuba Solutions.
# Copyright (c) 2001 ActiveState Corporation.
# Copyright (c) 2001-2002 David Gravereaux.
#
#------------------------------------------------------------------------------
# RCS: @(#) $Id: makefile.vc,v 1.107.2.3 2003/10/16 02:28:04 dgp Exp $
#------------------------------------------------------------------------------

!if "$(MSVCDIR)" == ""
MSG = ^
You'll need to run vcvars32.bat from Developer Studio, first, to setup^
the environment.  Jump to this line to read the new instructions.
!error $(MSG)











|


|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#------------------------------------------------------------------------------
# makefile.vc --
#
#	Microsoft Visual C++ makefile for use with nmake.exe v1.62+ (VC++ 5.0+)
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# Copyright (c) 1995-1996 Sun Microsystems, Inc.
# Copyright (c) 1998-2000 Ajuba Solutions.
# Copyright (c) 2001 ActiveState Corporation.
# Copyright (c) 2001-2004 David Gravereaux.
#
#------------------------------------------------------------------------------
# RCS: @(#) $Id: makefile.vc,v 1.107.2.4 2004/02/07 05:48:12 dgp Exp $
#------------------------------------------------------------------------------

!if "$(MSVCDIR)" == ""
MSG = ^
You'll need to run vcvars32.bat from Developer Studio, first, to setup^
the environment.  Jump to this line to read the new instructions.
!error $(MSG)
89
90
91
92
93
94
95








96
97
98
99
100
101
102
#		Sets optional memory and bytecode compiler debugging code added
#		to the core.  The default is for none.  Any combination of the
#		above may be used (comma separated).  'none' will over-ride
#		everything to nothing.
#
#		memdbg   = Enables the debugging memory allocator.
#		compdbg  = Enables byte compilation logging.








#
#	MACHINE=(IX86|IA64|ALPHA)
#		Set the machine type used for the compiler, linker, and
#		resource compiler.  This hook is needed to tell the tools
#		when alternate platforms are requested.  IX86 is the default
#		when not specified.
#







>
>
>
>
>
>
>
>







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#		Sets optional memory and bytecode compiler debugging code added
#		to the core.  The default is for none.  Any combination of the
#		above may be used (comma separated).  'none' will over-ride
#		everything to nothing.
#
#		memdbg   = Enables the debugging memory allocator.
#		compdbg  = Enables byte compilation logging.
#
#	CHECKS=nodep,fullwarn,none
#		Sets special macros for checking compatability.
#
#		nodep	 = Turns off compatability macros to ensure the core
#			    isn't being built with deprecated functions. 
#		fullwarn = Builds with full compiler and link warnings enabled.
#			    Very verbose.
#
#	MACHINE=(IX86|IA64|ALPHA)
#		Set the machine type used for the compiler, linker, and
#		resource compiler.  This hook is needed to tell the tools
#		when alternate platforms are requested.  IX86 is the default
#		when not specified.
#
155
156
157
158
159
160
161


162









163
164
165
166
167
168
169
170
171
172
!error $(MSG)
!endif

PROJECT	= tcl
!include "rules.vc"

STUBPREFIX = $(PROJECT)stub


DOTVERSION = 8.5









VERSION = $(DOTVERSION:.=)

DDEDOTVERSION = 1.2
DDEVERSION = $(DDEDOTVERSION:.=)

REGDOTVERSION = 1.1
REGVERSION = $(REGDOTVERSION:.=)

BINROOT		= .
ROOT		= ..







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


|







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
!error $(MSG)
!endif

PROJECT	= tcl
!include "rules.vc"

STUBPREFIX = $(PROJECT)stub

!if [nmakehlp -g ../generic/tcl.h TCL_VERSION] == 85
DOTVERSION	= 8.5
!elseif [nmakehlp -g ../generic/tcl.h TCL_VERSION] == 86
DOTVERSION	= 8.6
!elseif [nmakehlp -g ../generic/tcl.h TCL_VERSION] == 90
DOTVERSION	= 9.0
!elseif [nmakehlp -g ../generic/tcl.h TCL_VERSION] == 0
MSG =^
Can't get version string from ../generic/tcl.h
!error $(MSG)
!endif
VERSION = $(DOTVERSION:.=)

DDEDOTVERSION = 1.3
DDEVERSION = $(DDEDOTVERSION:.=)

REGDOTVERSION = 1.1
REGVERSION = $(REGDOTVERSION:.=)

BINROOT		= .
ROOT		= ..
329
330
331
332
333
334
335
336
337
338
339
340
341
342







343
344
345
346
347
348
349
### This cranks the optimization level to maximize speed
cdebug	= -O2 -Op -Gs
!else
cdebug	=
!endif
!else if "$(MACHINE)" == "IA64"
### Warnings are too many, can't support warnings into errors.
cdebug	= -Z7 -Od
!else
cdebug	= -Z7 -WX -Od
!endif

### Declarations common to all compiler options
cflags = -nologo -c -W3 -YX -Fp$(TMP_DIR)^\








!if $(PENT_0F_ERRATA)
cflags = $(cflags) -QI0f
!endif

!if $(ITAN_B_ERRATA)
cflags = $(cflags) -QIA64_Bx







|

|



|
>
>
>
>
>
>
>







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
### This cranks the optimization level to maximize speed
cdebug	= -O2 -Op -Gs
!else
cdebug	=
!endif
!else if "$(MACHINE)" == "IA64"
### Warnings are too many, can't support warnings into errors.
cdebug	= -Z7 -Od -GZ
!else
cdebug	= -Z7 -WX -Od -GZ
!endif

### Declarations common to all compiler options
cflags = -nologo -c -YX -Fp$(TMP_DIR)^\

!if $(FULLWARNINGS)
cflags = $(cflags) -W4
!else
cflags = $(cflags) -W3
!endif


!if $(PENT_0F_ERRATA)
cflags = $(cflags) -QI0f
!endif

!if $(ITAN_B_ERRATA)
cflags = $(cflags) -QIA64_Bx
379
380
381
382
383
384
385




386
387
388
389
390
391
392
ldebug	= -debug:full -debugtype:cv
!else
ldebug	= -release -opt:ref -opt:icf,3
!endif

### Declarations common to all linker options
lflags	= -nologo -machine:$(MACHINE) $(ldebug)





!if $(PROFILE)
lflags	= $(lflags) -profile
!endif

!if $(ALIGN98_HACK) && !$(STATIC_BUILD)
### Align sections for PE size savings.







>
>
>
>







405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
ldebug	= -debug:full -debugtype:cv
!else
ldebug	= -release -opt:ref -opt:icf,3
!endif

### Declarations common to all linker options
lflags	= -nologo -machine:$(MACHINE) $(ldebug)

!if $(FULLWARNINGS)
lflags = $(lflags) -warn:3
!endif

!if $(PROFILE)
lflags	= $(lflags) -profile
!endif

!if $(ALIGN98_HACK) && !$(STATIC_BUILD)
### Align sections for PE size savings.
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
lflags	= $(lflags) -ws:aggressive
!endif

dlllflags = $(lflags) -dll
conlflags = $(lflags) -subsystem:console
guilflags = $(lflags) -subsystem:windows

baselibs   = kernel32.lib advapi32.lib user32.lib


#---------------------------------------------------------------------
# TclTest flags
#---------------------------------------------------------------------

!IF "$(TESTPAT)" != ""







|







430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
lflags	= $(lflags) -ws:aggressive
!endif

dlllflags = $(lflags) -dll
conlflags = $(lflags) -subsystem:console
guilflags = $(lflags) -subsystem:windows

baselibs   = kernel32.lib user32.lib


#---------------------------------------------------------------------
# TclTest flags
#---------------------------------------------------------------------

!IF "$(TESTPAT)" != ""
604
605
606
607
608
609
610
611
612
613

614
615
616
617
618
619
620
621
622


#---------------------------------------------------------------------
# Special case object file targets
#---------------------------------------------------------------------

$(TMP_DIR)\testMain.obj: $(WINDIR)\tclAppInit.c
!if $(TCL_USE_STATIC_PACKAGES)
	$(cc32) $(TCL_CFLAGS) -DTCL_TEST -DTCL_USE_STATIC_PACKAGES -Fo$@ $?
!else

	$(cc32) $(TCL_CFLAGS) -DTCL_TEST -Fo$@ $?
!endif

$(TMP_DIR)\tclTest.obj: $(GENERICDIR)\tclTest.c
	$(cc32) $(TCL_CFLAGS) -Fo$@ $?

$(TMP_DIR)\tclTestObj.obj: $(GENERICDIR)\tclTestObj.c
	$(cc32) $(TCL_CFLAGS) -Fo$@ $?








<
|
<
>
|
<







634
635
636
637
638
639
640

641

642
643

644
645
646
647
648
649
650


#---------------------------------------------------------------------
# Special case object file targets
#---------------------------------------------------------------------

$(TMP_DIR)\testMain.obj: $(WINDIR)\tclAppInit.c

	$(cc32) $(TCL_CFLAGS) -DTCL_TEST \

	    -DTCL_USE_STATIC_PACKAGES=$(TCL_USE_STATIC_PACKAGES) \
	    -Fo$@ $?


$(TMP_DIR)\tclTest.obj: $(GENERICDIR)\tclTest.c
	$(cc32) $(TCL_CFLAGS) -Fo$@ $?

$(TMP_DIR)\tclTestObj.obj: $(GENERICDIR)\tclTestObj.c
	$(cc32) $(TCL_CFLAGS) -Fo$@ $?

634
635
636
637
638
639
640
641
642
643

644
645
646
647
648
649
650
651
652
	-DCFG_RUNTIME_BINDIR="\"$(BIN_INSTALL_DIR:\=\\)\"" \
	-DCFG_RUNTIME_SCRDIR="\"$(SCRIPT_INSTALL_DIR:\=\\)\"" \
	-DCFG_RUNTIME_INCDIR="\"$(INCLUDE_INSTALL_DIR:\=\\)\"" \
	-DCFG_RUNTIME_DOCDIR="\"$(DOC_INSTALL_DIR:\=\\)\""     \
	-Fo$@ $?

$(TMP_DIR)\tclAppInit.obj: $(WINDIR)\tclAppInit.c
!if $(TCL_USE_STATIC_PACKAGES)
	$(cc32) $(TCL_CFLAGS) -DTCL_USE_STATIC_PACKAGES -Fo$@ $?
!else

	$(cc32) $(TCL_CFLAGS) -Fo$@ $?
!endif

### The following objects should be built using the stub interfaces
### *ALL* extensions need to built with -DTCL_THREADS=1

$(TMP_DIR)\tclWinReg.obj: $(WINDIR)\tclWinReg.c
!if $(STATIC_BUILD)
	$(cc32) $(TCL_CFLAGS) -DTCL_THREADS=1 -DSTATIC_BUILD -Fo$@ $?







<
|
<
>
|
<







662
663
664
665
666
667
668

669

670
671

672
673
674
675
676
677
678
	-DCFG_RUNTIME_BINDIR="\"$(BIN_INSTALL_DIR:\=\\)\"" \
	-DCFG_RUNTIME_SCRDIR="\"$(SCRIPT_INSTALL_DIR:\=\\)\"" \
	-DCFG_RUNTIME_INCDIR="\"$(INCLUDE_INSTALL_DIR:\=\\)\"" \
	-DCFG_RUNTIME_DOCDIR="\"$(DOC_INSTALL_DIR:\=\\)\""     \
	-Fo$@ $?

$(TMP_DIR)\tclAppInit.obj: $(WINDIR)\tclAppInit.c

	$(cc32) $(TCL_CFLAGS) \

	    -DTCL_USE_STATIC_PACKAGES=$(TCL_USE_STATIC_PACKAGES) \
	    -Fo$@ $?


### The following objects should be built using the stub interfaces
### *ALL* extensions need to built with -DTCL_THREADS=1

$(TMP_DIR)\tclWinReg.obj: $(WINDIR)\tclWinReg.c
!if $(STATIC_BUILD)
	$(cc32) $(TCL_CFLAGS) -DTCL_THREADS=1 -DSTATIC_BUILD -Fo$@ $?
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

{$(COMPATDIR)}.c{$(TMP_DIR)}.obj::
    $(cc32) $(TCL_CFLAGS) -DBUILD_tcl -Fo$(TMP_DIR)\ @<<
$<
<<

{$(WINDIR)}.rc{$(TMP_DIR)}.res:
	$(rc32) -fo $@ -r -i "$(GENERICDIR)" -D__WIN32__ \
!if $(DEBUG)
	-d DEBUG \
!endif
!if $(TCL_THREADS)
	-d TCL_THREADS \
!endif
!if $(STATIC_BUILD)
	-d STATIC_BUILD \
!endif
	$<

.SUFFIXES:
.SUFFIXES:.c .rc


#---------------------------------------------------------------------
# Installation.







|
<
<
<
<
|
<
<
|
<
|







747
748
749
750
751
752
753
754




755


756

757
758
759
760
761
762
763
764

{$(COMPATDIR)}.c{$(TMP_DIR)}.obj::
    $(cc32) $(TCL_CFLAGS) -DBUILD_tcl -Fo$(TMP_DIR)\ @<<
$<
<<

{$(WINDIR)}.rc{$(TMP_DIR)}.res:
	$(rc32) -fo $@ -r -i "$(GENERICDIR)" \




	    -d DEBUG=$(DEBUG) -d TCL_THREADS=$(TCL_THREADS) \


	    -d STATIC_BUILD=$(STATIC_BUILD) \

	    $<

.SUFFIXES:
.SUFFIXES:.c .rc


#---------------------------------------------------------------------
# Installation.
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
		"$(SCRIPT_INSTALL_DIR)\http1.0\"
	@echo installing http2.4
	@$(CPY) "$(ROOT)\library\http\*.tcl" \
		"$(SCRIPT_INSTALL_DIR)\http2.4\"
	@echo installing opt0.4
	@$(CPY) "$(ROOT)\library\opt\*.tcl" \
		"$(SCRIPT_INSTALL_DIR)\opt0.4\"
	@echo installing msgcat1.3
	@$(CPY) "$(ROOT)\library\msgcat\*.tcl" \
	    "$(SCRIPT_INSTALL_DIR)\msgcat1.3\"
	@echo installing tcltest2.2 
	@$(CPY) "$(ROOT)\library\tcltest\*.tcl" \
	    "$(SCRIPT_INSTALL_DIR)\tcltest2.2\"
	@echo installing $(TCLDDELIBNAME)
!if $(STATIC_BUILD)
	@$(CPY) "$(TCLDDELIB)" "$(LIB_INSTALL_DIR)\"
!else







|

|







788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
		"$(SCRIPT_INSTALL_DIR)\http1.0\"
	@echo installing http2.4
	@$(CPY) "$(ROOT)\library\http\*.tcl" \
		"$(SCRIPT_INSTALL_DIR)\http2.4\"
	@echo installing opt0.4
	@$(CPY) "$(ROOT)\library\opt\*.tcl" \
		"$(SCRIPT_INSTALL_DIR)\opt0.4\"
	@echo installing msgcat1.4
	@$(CPY) "$(ROOT)\library\msgcat\*.tcl" \
	    "$(SCRIPT_INSTALL_DIR)\msgcat1.4\"
	@echo installing tcltest2.2 
	@$(CPY) "$(ROOT)\library\tcltest\*.tcl" \
	    "$(SCRIPT_INSTALL_DIR)\tcltest2.2\"
	@echo installing $(TCLDDELIBNAME)
!if $(STATIC_BUILD)
	@$(CPY) "$(TCLDDELIB)" "$(LIB_INSTALL_DIR)\"
!else
814
815
816
817
818
819
820

821
822



823
824
825
826
827
828
829


#---------------------------------------------------------------------
# Clean up
#---------------------------------------------------------------------

tidy:

	@echo Removing $(TCLLIB) ...
	@if exist $(TCLLIB) del $(TCLLIB)



	@echo Removing $(TCLSH) ...
	@if exist $(TCLSH) del $(TCLSH)
	@echo Removing $(TCLTEST) ...
	@if exist $(TCLTEST) del $(TCLTEST)
	@echo Removing $(TCLDDELIB) ...
	@if exist $(TCLDDELIB) del $(TCLDDELIB)
	@echo Removing $(TCLREGLIB) ...







>


>
>
>







833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852


#---------------------------------------------------------------------
# Clean up
#---------------------------------------------------------------------

tidy:
!if "$(TCLLIB)" != "$(TCLIMPLIB)"
	@echo Removing $(TCLLIB) ...
	@if exist $(TCLLIB) del $(TCLLIB)
!endif
	@echo Removing $(TCLIMPLIB) ...
	@if exist $(TCLIMPLIB) del $(TCLIMPLIB)
	@echo Removing $(TCLSH) ...
	@if exist $(TCLSH) del $(TCLSH)
	@echo Removing $(TCLTEST) ...
	@if exist $(TCLTEST) del $(TCLTEST)
	@echo Removing $(TCLDDELIB) ...
	@if exist $(TCLDDELIB) del $(TCLDDELIB)
	@echo Removing $(TCLREGLIB) ...
Changes to win/nmakehlp.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

18
19
20
21
22

23
24
25


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42







43
44
45
46
47
48
49
/* ----------------------------------------------------------------------------
 * nmakehlp.c --
 *
 *	This is used to fix limitations within nmake and the environment.
 *
 * Copyright (c) 2002 by David Gravereaux.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * ----------------------------------------------------------------------------
 * RCS: @(#) $Id: nmakehlp.c,v 1.1 2002/03/27 21:15:43 davygrvy Exp $
 * ----------------------------------------------------------------------------
 */
#include <windows.h>
#pragma comment (lib, "user32.lib")
#pragma comment (lib, "kernel32.lib")


/* protos */
int CheckForCompilerFeature (const char *option);
int CheckForLinkerFeature (const char *option);
int IsIn (const char *string, const char *substring);

DWORD WINAPI ReadFromPipe (LPVOID args);

/* globals */


typedef struct {
    HANDLE pipe;
    char buffer[1000];
} pipeinfo;

pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'};
pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'};



/* exitcodes: 0 == no, 1 == yes, 2 == error */
int
main (int argc, char *argv[])
{
    char msg[300];
    DWORD dwWritten;
    int chars;








    if (argc > 1 && *argv[1] == '-') {
	switch (*(argv[1]+1)) {
	case 'c':
	    if (argc != 3) {
		chars = wsprintf(msg, "usage: %s -c <compiler option>\n"
			"Tests for whether cl.exe supports an option\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
48
49
50
51
52
53
54
55
56
57
58
59
60
/* ----------------------------------------------------------------------------
 * nmakehlp.c --
 *
 *	This is used to fix limitations within nmake and the environment.
 *
 * Copyright (c) 2002 by David Gravereaux.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * ----------------------------------------------------------------------------
 * RCS: @(#) $Id: nmakehlp.c,v 1.1.6.1 2004/02/07 05:48:12 dgp Exp $
 * ----------------------------------------------------------------------------
 */
#include <windows.h>
#pragma comment (lib, "user32.lib")
#pragma comment (lib, "kernel32.lib")
#include <stdio.h>

/* protos */
int CheckForCompilerFeature (const char *option);
int CheckForLinkerFeature (const char *option);
int IsIn (const char *string, const char *substring);
int GrepForDefine (const char *file, const char *string);
DWORD WINAPI ReadFromPipe (LPVOID args);

/* globals */
#define CHUNK	25
#define STATICBUFFERSIZE    1000
typedef struct {
    HANDLE pipe;
    char buffer[STATICBUFFERSIZE];
} pipeinfo;

pipeinfo Out = {INVALID_HANDLE_VALUE, '\0'};
pipeinfo Err = {INVALID_HANDLE_VALUE, '\0'};



/* exitcodes: 0 == no, 1 == yes, 2 == error */
int
main (int argc, char *argv[])
{
    char msg[300];
    DWORD dwWritten;
    int chars;

    /* make sure children (cl.exe and link.exe) are kept quiet. */
    SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);

    /* Make sure the compiler and linker aren't effected by the outside world. */
    SetEnvironmentVariable("CL", "");
    SetEnvironmentVariable("LINK", "");

    if (argc > 1 && *argv[1] == '-') {
	switch (*(argv[1]+1)) {
	case 'c':
	    if (argc != 3) {
		chars = wsprintf(msg, "usage: %s -c <compiler option>\n"
			"Tests for whether cl.exe supports an option\n"
70
71
72
73
74
75
76









77
78
79
80
81
82
83
		return 2;
	    } else if (argc == 3) {
		/* if the string is blank, there is no match */
		return 0;
	    } else {
		return IsIn(argv[2], argv[3]);
	    }









	}
    }
    chars = wsprintf(msg, "usage: %s -c|-l|-f ...\n"
	    "This is a little helper app to equalize shell differences between WinNT and\n"
	    "Win9x and get nmake.exe to accomplish its job.\n",
	    argv[0]);
    WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);







>
>
>
>
>
>
>
>
>







81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
		return 2;
	    } else if (argc == 3) {
		/* if the string is blank, there is no match */
		return 0;
	    } else {
		return IsIn(argv[2], argv[3]);
	    }
	case 'g':
	    if (argc == 2) {
		chars = wsprintf(msg, "usage: %s -g <file> <string>\n"
		    "grep for a #define\n"
		    "exitcodes: integer of the found string (no decimals)\n", argv[0]);
		WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
		return 2;
	    }
	    return GrepForDefine(argv[2], argv[3]);
	}
    }
    chars = wsprintf(msg, "usage: %s -c|-l|-f ...\n"
	    "This is a little helper app to equalize shell differences between WinNT and\n"
	    "Win9x and get nmake.exe to accomplish its job.\n",
	    argv[0]);
    WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136

    /* Same as above, but for the error side. */
    CreatePipe(&Err.pipe, &h, &sa, 0);
    DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 
	    0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);

    /* base command line */
    strcpy(cmdline, "cl.exe -nologo -c -TC -Fdtemp ");
    /* append our option for testing */
    strcat(cmdline, option);
    /* filename to compile, which exists, but is nothing and empty. */
    strcat(cmdline, " nul");

    ok = CreateProcess(
	    NULL,	    /* Module name. */
	    cmdline,	    /* Command line. */
	    NULL,	    /* Process handle not inheritable. */
	    NULL,	    /* Thread handle not inheritable. */
	    TRUE,	    /* yes, inherit handles. */







|



|







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

    /* Same as above, but for the error side. */
    CreatePipe(&Err.pipe, &h, &sa, 0);
    DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 
	    0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);

    /* base command line */
    strcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X ");
    /* append our option for testing */
    strcat(cmdline, option);
    /* filename to compile, which exists, but is nothing and empty. */
    strcat(cmdline, " .\\nul");

    ok = CreateProcess(
	    NULL,	    /* Module name. */
	    cmdline,	    /* Command line. */
	    NULL,	    /* Process handle not inheritable. */
	    NULL,	    /* Thread handle not inheritable. */
	    TRUE,	    /* yes, inherit handles. */
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
    pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
    pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);

    /* block waiting for the process to end. */
    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);

    /* clean up temporary files before returning */
    DeleteFile("temp.idb");
    DeleteFile("temp.pdb");

    /* wait for our pipe to get done reading, should it be a little slow. */
    WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
    CloseHandle(pipeThreads[0]);
    CloseHandle(pipeThreads[1]);

    /* look for the commandline warning code in both streams. */
    return !(strstr(Out.buffer, "D4002") != NULL || strstr(Err.buffer, "D4002") != NULL);







<
<
<
<







182
183
184
185
186
187
188




189
190
191
192
193
194
195
    pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
    pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);

    /* block waiting for the process to end. */
    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);





    /* wait for our pipe to get done reading, should it be a little slow. */
    WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
    CloseHandle(pipeThreads[0]);
    CloseHandle(pipeThreads[1]);

    /* look for the commandline warning code in both streams. */
    return !(strstr(Out.buffer, "D4002") != NULL || strstr(Err.buffer, "D4002") != NULL);
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
    DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 
	    0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);

    /* base command line */
    strcpy(cmdline, "link.exe -nologo ");
    /* append our option for testing */
    strcat(cmdline, option);
    /* filename to compile, which exists, but is nothing and empty. */
//    strcat(cmdline, " nul");

    ok = CreateProcess(
	    NULL,	    /* Module name. */
	    cmdline,	    /* Command line. */
	    NULL,	    /* Process handle not inheritable. */
	    NULL,	    /* Thread handle not inheritable. */
	    TRUE,	    /* yes, inherit handles. */







<
<







232
233
234
235
236
237
238


239
240
241
242
243
244
245
    DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 
	    0, TRUE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);

    /* base command line */
    strcpy(cmdline, "link.exe -nologo ");
    /* append our option for testing */
    strcat(cmdline, option);



    ok = CreateProcess(
	    NULL,	    /* Module name. */
	    cmdline,	    /* Command line. */
	    NULL,	    /* Process handle not inheritable. */
	    NULL,	    /* Thread handle not inheritable. */
	    TRUE,	    /* yes, inherit handles. */
275
276
277
278
279
280
281




282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297








































{
    pipeinfo *pi = (pipeinfo *) args;
    char *lastBuf = pi->buffer;
    DWORD dwRead;
    BOOL ok;

again:




    ok = ReadFile(pi->pipe, lastBuf, 25, &dwRead, 0L);
    if (!ok || dwRead == 0) {
	CloseHandle(pi->pipe);
	return 0;
    }
    lastBuf += dwRead;
    goto again;

    return 0;  /* makes the compiler happy */
}

int
IsIn (const char *string, const char *substring)
{
    return (strstr(string, substring) != NULL);
}















































>
>
>
>
|















>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
{
    pipeinfo *pi = (pipeinfo *) args;
    char *lastBuf = pi->buffer;
    DWORD dwRead;
    BOOL ok;

again:
    if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) {
	CloseHandle(pi->pipe);
	return -1;
    }
    ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L);
    if (!ok || dwRead == 0) {
	CloseHandle(pi->pipe);
	return 0;
    }
    lastBuf += dwRead;
    goto again;

    return 0;  /* makes the compiler happy */
}

int
IsIn (const char *string, const char *substring)
{
    return (strstr(string, substring) != NULL);
}

/*
 *  Find a specified #define by name.
 *
 *  If the line is '#define TCL_VERSION "8.5"', it returns
 *  85 as the result.
 */

int
GrepForDefine (const char *file, const char *string)
{
    FILE *f;
    char s1[51], s2[51], s3[51];
    int r = 0;
    double d1;

    f = fopen(file, "rt");
    if (f == NULL) {
	return 0;
    }

    do {
	r = fscanf(f, "%50s", s1);
	if (r == 1 && !strcmp(s1, "#define")) {
	    /* get next two words */
	    r = fscanf(f, "%50s %50s", s2, s3);
	    if (r != 2) continue;
	    /* is the first word what we're looking for? */
	    if (!strcmp(s2, string)) {
		fclose(f);
		/* add 1 past first double quote char. "8.5" */
		d1 = atof(s3 + 1);		  /*    8.5  */
		return ((int) (d1 * 10) & 0xFF);  /*    85   */
	    }
	}
    } while (!feof(f));

    fclose(f);
    return 0;
}
Changes to win/rules.vc.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#------------------------------------------------------------------------------
# rules.vc --
#
#	Microsoft Visual C++ makefile include for decoding the commandline
#	macros.  This file does not need editing to build Tcl.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# Copyright (c) 2001-2002 David Gravereaux.
#
#------------------------------------------------------------------------------
# RCS: @(#) $Id: rules.vc,v 1.12.2.2 2003/08/07 21:36:05 dgp Exp $
#------------------------------------------------------------------------------

!ifndef _RULES_VC
_RULES_VC = 1

cc32		= $(CC)   # built-in default.
link32		= link









|


|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#------------------------------------------------------------------------------
# rules.vc --
#
#	Microsoft Visual C++ makefile include for decoding the commandline
#	macros.  This file does not need editing to build Tcl.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
# 
# Copyright (c) 2001-2003 David Gravereaux.
#
#------------------------------------------------------------------------------
# RCS: @(#) $Id: rules.vc,v 1.12.2.3 2004/02/07 05:48:12 dgp Exp $
#------------------------------------------------------------------------------

!ifndef _RULES_VC
_RULES_VC = 1

cc32		= $(CC)   # built-in default.
link32		= link
260
261
262
263
264
265
266























267
268
269
270
271
272
273
!message *** Doing compdbg
TCL_COMPILE_DEBUG   = 1
!else
TCL_COMPILE_DEBUG   = 0
!endif
!endif

























#----------------------------------------------------------
# Set our defines now armed with our options.
#----------------------------------------------------------

OPTDEFINES	= -DTCL_CFGVAL_ENCODING=$(CFG_ENCODING)








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







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
!message *** Doing compdbg
TCL_COMPILE_DEBUG   = 1
!else
TCL_COMPILE_DEBUG   = 0
!endif
!endif


#----------------------------------------------------------
# Decode the checks requested.
#----------------------------------------------------------

!if "$(CHECKS)" == "" || [nmakehlp -f "$(CHECKS)" "none"]
TCL_NO_DEPRECATED	    = 0
FULLWARNINGS		    = 0
!else
!if [nmakehlp -f $(CHECKS) "nodep"]
!message *** Doing nodep check
TCL_NO_DEPRECATED	    = 1
!else
TCL_NO_DEPRECATED	    = 0
!endif
!if [nmakehlp -f $(CHECKS) "fullwarn"]
!message *** Doing full warnings check
FULLWARNINGS		    = 1
!else
FULLWARNINGS		    = 0
!endif
!endif


#----------------------------------------------------------
# Set our defines now armed with our options.
#----------------------------------------------------------

OPTDEFINES	= -DTCL_CFGVAL_ENCODING=$(CFG_ENCODING)

282
283
284
285
286
287
288



289
290
291
292
293
294
295
!if $(USE_THREAD_ALLOC)
OPTDEFINES	= $(OPTDEFINES) -DUSE_THREAD_ALLOC=1
!endif
!endif
!if $(STATIC_BUILD)
OPTDEFINES	= $(OPTDEFINES) -DSTATIC_BUILD
!endif




!if $(DEBUG)
OPTDEFINES	= $(OPTDEFINES) -DTCL_CFG_DEBUG
!elseif $(OPTIMIZING)
OPTDEFINES	= $(OPTDEFINES) -DTCL_CFG_OPTIMIZED
!endif
!if $(PROFILE)







>
>
>







305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
!if $(USE_THREAD_ALLOC)
OPTDEFINES	= $(OPTDEFINES) -DUSE_THREAD_ALLOC=1
!endif
!endif
!if $(STATIC_BUILD)
OPTDEFINES	= $(OPTDEFINES) -DSTATIC_BUILD
!endif
!if $(TCL_NO_DEPRECATED)
OPTDEFINES	= $(OPTDEFINES) -DTCL_NO_DEPRECATED
!endif

!if $(DEBUG)
OPTDEFINES	= $(OPTDEFINES) -DTCL_CFG_DEBUG
!elseif $(OPTIMIZING)
OPTDEFINES	= $(OPTDEFINES) -DTCL_CFG_OPTIMIZED
!endif
!if $(PROFILE)
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
# Get common info used when building extensions.
#----------------------------------------------------------

!if "$(PROJECT)" != "tcl"

!if !defined(TCLDIR)
!if exist("$(_INSTALLDIR)\include\tcl.h")

TCLINSTALL	= 1
_TCLDIR		= $(_INSTALLDIR)
!else
MSG=^
Don't know where tcl.h is.  Set the TCLDIR macro.
!error $(MSG)
!endif
!else
_TCLDIR	= $(TCLDIR:/=\)
!if exist("$(_TCLDIR)\include\tcl.h")

TCLINSTALL	= 1
!elseif exist("$(_TCLDIR)\generic\tcl.h")

TCLINSTALL	= 0
!else
MSG =^
Don't know where tcl.h is.  The TCLDIR macro doesn't appear correct.
!error $(MSG)
!endif
!endif


### TODO: add a command to nmakehlp.c to grep for Tcl's version from tcl.h.


### Because nmake can't return a string, we'll need to play games with return
### codes.  It might look something like this:
#!if [nmakehlp -g $(TCL.H)] == 81




#TCL_DOTVERSION	= 8.1
#!elseif [nmakehlp -g $(TCL.H)] == 82
#TCL_DOTVERSION	= 8.2
#...














#!endif

TCL_DOTVERSION	= 8.5
TCL_VERSION	= $(TCL_DOTVERSION:.=)







!if $(TCLINSTALL)
TCLSH		= "$(_INSTALLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe"
TCLSTUBLIB	= "$(_INSTALLDIR)\lib\tclstub$(TCL_VERSION).lib"
TCLIMPLIB	= "$(_INSTALLDIR)\lib\tcl$(TCL_VERSION)$(SUFX).lib"
TCL_LIBRARY	= $(_INSTALLDIR)\lib
TCLREGLIB	= "$(_INSTALLDIR)\lib\tclreg11$(SUFX:t=).lib"







>










>


>








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

<

>
>
>
>
>
>







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
# Get common info used when building extensions.
#----------------------------------------------------------

!if "$(PROJECT)" != "tcl"

!if !defined(TCLDIR)
!if exist("$(_INSTALLDIR)\include\tcl.h")
TCLH		= "$(_INSTALLDIR)\include\tcl.h"
TCLINSTALL	= 1
_TCLDIR		= $(_INSTALLDIR)
!else
MSG=^
Don't know where tcl.h is.  Set the TCLDIR macro.
!error $(MSG)
!endif
!else
_TCLDIR	= $(TCLDIR:/=\)
!if exist("$(_TCLDIR)\include\tcl.h")
TCLH		= "$(_TCLDIR)\include\tcl.h"
TCLINSTALL	= 1
!elseif exist("$(_TCLDIR)\generic\tcl.h")
TCLH		= "$(_TCLDIR)\generic\tcl.h"
TCLINSTALL	= 0
!else
MSG =^
Don't know where tcl.h is.  The TCLDIR macro doesn't appear correct.
!error $(MSG)
!endif
!endif

#----------------------------------------------------------
# Get the version from the header file.  Try all possibles
# even though some aren't fully valid.
#----------------------------------------------------------


!if [nmakehlp -g $(TCLH) TCL_VERSION] == 76
TCL_DOTVERSION	= 7.6
!elseif [nmakehlp -g $(TCLH) TCL_VERSION] == 80
TCL_DOTVERSION	= 8.0
!elseif [nmakehlp -g $(TCLH) TCL_VERSION] == 81
TCL_DOTVERSION	= 8.1
!elseif [nmakehlp -g $(TCLH) TCL_VERSION] == 82
TCL_DOTVERSION	= 8.2

!elseif [nmakehlp -g $(TCLH) TCL_VERSION] == 83
TCL_DOTVERSION	= 8.3
!elseif [nmakehlp -g $(TCLH) TCL_VERSION] == 84
TCL_DOTVERSION	= 8.4
!elseif [nmakehlp -g $(TCLH) TCL_VERSION] == 85
TCL_DOTVERSION	= 8.5
!elseif [nmakehlp -g $(TCLH) TCL_VERSION] == 86
TCL_DOTVERSION	= 8.6
!elseif [nmakehlp -g $(TCLH) TCL_VERSION] == 90
TCL_DOTVERSION	= 9.0
!elseif [nmakehlp -g $(TCLH) TCL_VERSION] == 0
MSG =^
Can't get version string from $(TCLH)
!error $(MSG)
!endif


TCL_VERSION	= $(TCL_DOTVERSION:.=)

!if $(TCL_VERSION) < 81
TCL_DOES_STUBS	= 0
!else
TCL_DOES_STUBS	= 1
!endif

!if $(TCLINSTALL)
TCLSH		= "$(_INSTALLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe"
TCLSTUBLIB	= "$(_INSTALLDIR)\lib\tclstub$(TCL_VERSION).lib"
TCLIMPLIB	= "$(_INSTALLDIR)\lib\tcl$(TCL_VERSION)$(SUFX).lib"
TCL_LIBRARY	= $(_INSTALLDIR)\lib
TCLREGLIB	= "$(_INSTALLDIR)\lib\tclreg11$(SUFX:t=).lib"
Changes to win/tcl.rc.
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
// RCS: @(#) $Id: tcl.rc,v 1.8 2002/06/18 00:12:24 davygrvy Exp $
//
// Version Resource Script
//

#include <winver.h>
#include <tcl.h>

//
// build-up the name suffix that defines the type of build this is.
//
#ifdef TCL_THREADS
#define SUFFIX_THREADS	    "t"
#else
#define SUFFIX_THREADS	    ""
#endif

#ifdef DEBUG
#define SUFFIX_DEBUG	    "d"
#else
#define SUFFIX_DEBUG	    ""
#endif

#define SUFFIX		    SUFFIX_THREADS SUFFIX_DEBUG


|










|





|
|







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
// RCS: @(#) $Id: tcl.rc,v 1.8.4.1 2004/02/07 05:48:12 dgp Exp $
//
// Version Resource Script
//

#include <winver.h>
#include <tcl.h>

//
// build-up the name suffix that defines the type of build this is.
//
#if TCL_THREADS
#define SUFFIX_THREADS	    "t"
#else
#define SUFFIX_THREADS	    ""
#endif

#if DEBUG
#define SUFFIX_DEBUG	    "g"
#else
#define SUFFIX_DEBUG	    ""
#endif

#define SUFFIX		    SUFFIX_THREADS SUFFIX_DEBUG


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 FILESUBTYPE 	0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904b0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */
        BEGIN
            VALUE "FileDescription", "Tcl DLL\0"
            VALUE "OriginalFilename", "tcl" STRINGIFY(JOIN(TCL_MAJOR_VERSION,TCL_MINOR_VERSION)) SUFFIX ".dll\0"
            VALUE "CompanyName", "ActiveState Corporation\0"
            VALUE "FileVersion", TCL_PATCH_LEVEL
            VALUE "LegalCopyright", "Copyright \251 2001 by ActiveState Corporation, et al\0"
            VALUE "ProductName", "Tcl " TCL_VERSION " for Windows\0"
            VALUE "ProductVersion", TCL_PATCH_LEVEL
        END		    
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x409, 1200
    END
END







|












40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 FILESUBTYPE 	0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904b0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */
        BEGIN
            VALUE "FileDescription", "Tcl DLL\0"
            VALUE "OriginalFilename", "tcl" STRINGIFY(TCL_MAJOR_VERSION) STRINGIFY(TCL_MINOR_VERSION) SUFFIX ".dll\0"
            VALUE "CompanyName", "ActiveState Corporation\0"
            VALUE "FileVersion", TCL_PATCH_LEVEL
            VALUE "LegalCopyright", "Copyright \251 2001 by ActiveState Corporation, et al\0"
            VALUE "ProductName", "Tcl " TCL_VERSION " for Windows\0"
            VALUE "ProductVersion", TCL_PATCH_LEVEL
        END		    
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x409, 1200
    END
END
Changes to win/tclAppInit.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/*
 * tclAppInit.c --
 *
 *	Provides a default version of the main program and Tcl_AppInit
 *	procedure for Tcl applications (without Tk).  Note that this
 *	program must be built in Win32 console mode to work properly.
 *
 * Copyright (c) 1996-1997 by 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.
 *
 * RCS: @(#) $Id: tclAppInit.c,v 1.13.2.1 2003/10/16 02:28:04 dgp Exp $
 */

#include "tcl.h"
#include <windows.h>
#include <locale.h>

#ifdef TCL_TEST
extern int		Procbodytest_Init _ANSI_ARGS_((Tcl_Interp *interp));
extern int		Procbodytest_SafeInit _ANSI_ARGS_((Tcl_Interp *interp));
extern int		Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp));
extern int		TclObjTest_Init _ANSI_ARGS_((Tcl_Interp *interp));
#ifdef TCL_THREADS
extern int		TclThread_Init _ANSI_ARGS_((Tcl_Interp *interp));
#endif
#endif /* TCL_TEST */

static void		setargv _ANSI_ARGS_((int *argcPtr, char ***argvPtr));
static BOOL __stdcall	sigHandler (DWORD fdwCtrlType);
static Tcl_AsyncProc	asyncExit;
static void		AppInitExitHandler(ClientData clientData);

static char **          argvSave = NULL;
static Tcl_AsyncHandler exitToken = NULL;
static DWORD            exitErrorCode = 0;


/*
 *----------------------------------------------------------------------
 *













|
















<
|



<







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
/*
 * tclAppInit.c --
 *
 *	Provides a default version of the main program and Tcl_AppInit
 *	procedure for Tcl applications (without Tk).  Note that this
 *	program must be built in Win32 console mode to work properly.
 *
 * Copyright (c) 1996-1997 by 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.
 *
 * RCS: @(#) $Id: tclAppInit.c,v 1.13.2.2 2004/02/07 05:48:12 dgp Exp $
 */

#include "tcl.h"
#include <windows.h>
#include <locale.h>

#ifdef TCL_TEST
extern int		Procbodytest_Init _ANSI_ARGS_((Tcl_Interp *interp));
extern int		Procbodytest_SafeInit _ANSI_ARGS_((Tcl_Interp *interp));
extern int		Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp));
extern int		TclObjTest_Init _ANSI_ARGS_((Tcl_Interp *interp));
#ifdef TCL_THREADS
extern int		TclThread_Init _ANSI_ARGS_((Tcl_Interp *interp));
#endif
#endif /* TCL_TEST */


static BOOL WINAPI	sigHandler (DWORD fdwCtrlType);
static Tcl_AsyncProc	asyncExit;
static void		AppInitExitHandler(ClientData clientData);


static Tcl_AsyncHandler exitToken = NULL;
static DWORD            exitErrorCode = 0;


/*
 *----------------------------------------------------------------------
 *
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
 * Side effects:
 *	Whatever the application does.
 *
 *----------------------------------------------------------------------
 */

int
main(argc, argv)
    int argc;			/* Number of command-line arguments. */
    char **argv;		/* Values of command-line arguments. */
{
    /*
     * The following #if block allows you to change the AppInit
     * function by using 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.
     */







|
<
<







50
51
52
53
54
55
56
57


58
59
60
61
62
63
64
 * Side effects:
 *	Whatever the application does.
 *
 *----------------------------------------------------------------------
 */

int
main (int argc, char *argv[])


{
    /*
     * The following #if block allows you to change the AppInit
     * function by using 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.
     */
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
     * etc., without needing to rewrite Tcl_Main()
     */

#ifdef TCL_LOCAL_MAIN_HOOK
    extern int TCL_LOCAL_MAIN_HOOK _ANSI_ARGS_((int *argc, char ***argv));
#endif

    char buffer[MAX_PATH +1];
    char *p;

    /*
     * Set up the default locale to be standard "C" locale so parsing
     * is performed correctly.
     */

    setlocale(LC_ALL, "C");
    setargv(&argc, &argv);

    /*
     * Save this for later, so we can free it.
     */
    argvSave = argv;

    /*
     * Replace argv[0] with full pathname of executable, and forward
     * slashes substituted for backslashes.
     */

    GetModuleFileName(NULL, buffer, sizeof(buffer));
    argv[0] = buffer;
    for (p = buffer; *p != '\0'; p++) {
	if (*p == '\\') {
	    *p = '/';
	}
    }

#ifdef TCL_LOCAL_MAIN_HOOK
    TCL_LOCAL_MAIN_HOOK(&argc, &argv);
#endif

    Tcl_Main(argc, argv, TCL_LOCAL_APPINIT);

    return 0;			/* Needed only to prevent compiler warning. */
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_AppInit --
 *
 *	This procedure performs application-specific initialization.







<

>






<


<
<
<
<
<
<
|


<
<
|













<







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
     * etc., without needing to rewrite Tcl_Main()
     */

#ifdef TCL_LOCAL_MAIN_HOOK
    extern int TCL_LOCAL_MAIN_HOOK _ANSI_ARGS_((int *argc, char ***argv));
#endif


    char *p;

    /*
     * Set up the default locale to be standard "C" locale so parsing
     * is performed correctly.
     */

    setlocale(LC_ALL, "C");


    /*






     * Forward slashes substituted for backslashes.
     */



    for (p = argv[0]; *p != '\0'; p++) {
	if (*p == '\\') {
	    *p = '/';
	}
    }

#ifdef TCL_LOCAL_MAIN_HOOK
    TCL_LOCAL_MAIN_HOOK(&argc, &argv);
#endif

    Tcl_Main(argc, argv, TCL_LOCAL_APPINIT);

    return 0;			/* Needed only to prevent compiler warning. */
}


/*
 *----------------------------------------------------------------------
 *
 * Tcl_AppInit --
 *
 *	This procedure performs application-specific initialization.
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
    if (Procbodytest_Init(interp) == TCL_ERROR) {
	return TCL_ERROR;
    }
    Tcl_StaticPackage(interp, "procbodytest", Procbodytest_Init,
            Procbodytest_SafeInit);
#endif /* TCL_TEST */

#if defined(STATIC_BUILD) && defined(TCL_USE_STATIC_PACKAGES)
    {
	extern Tcl_PackageInitProc Registry_Init;
	extern Tcl_PackageInitProc Dde_Init;

	if (Registry_Init(interp) == TCL_ERROR) {
	    return TCL_ERROR;
	}







|







162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
    if (Procbodytest_Init(interp) == TCL_ERROR) {
	return TCL_ERROR;
    }
    Tcl_StaticPackage(interp, "procbodytest", Procbodytest_Init,
            Procbodytest_SafeInit);
#endif /* TCL_TEST */

#if defined(STATIC_BUILD) && TCL_USE_STATIC_PACKAGES
    {
	extern Tcl_PackageInitProc Registry_Init;
	extern Tcl_PackageInitProc Dde_Init;

	if (Registry_Init(interp) == TCL_ERROR) {
	    return TCL_ERROR;
	}
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
 *	Frees the saved argv and deletes the async exit handler.
 *
 *----------------------------------------------------------------------
 */

static void
AppInitExitHandler(
    ClientData clientData)
{
    if (argvSave != NULL) {
        ckfree((char *)argvSave);
        argvSave = NULL;
    }

    if (exitToken != NULL) {
        /*
         * This should be safe to do even if we
         * are in an async exit right now.
         */
        Tcl_AsyncDelete(exitToken);
        exitToken = NULL;
    }
}

/*
 *-------------------------------------------------------------------------
 *
 * setargv --
 *
 *	Parse the Windows command line string into argc/argv.  Done here
 *	because we don't trust the builtin argument parser in crt0.
 *	Windows applications are responsible for breaking their command
 *	line into arguments.
 *
 *	2N backslashes + quote -> N backslashes + begin quoted string
 *	2N + 1 backslashes + quote -> literal
 *	N backslashes + non-quote -> literal
 *	quote + quote in a quoted string -> single quote
 *	quote + quote not in quoted string -> empty string
 *	quote -> begin quoted string
 *
 * Results:
 *	Fills argcPtr with the number of arguments and argvPtr with the
 *	array of arguments.
 *
 * Side effects:
 *	Memory allocated.
 *
 *--------------------------------------------------------------------------
 */

static void
setargv(argcPtr, argvPtr)
    int *argcPtr;		/* Filled with number of argument strings. */
    char ***argvPtr;		/* Filled with argument strings (malloc'd). */
{
    char *cmdLine, *p, *arg, *argSpace;
    char **argv;
    int argc, size, inquote, copy, slashes;

    cmdLine = GetCommandLine();	/* INTL: BUG */

    /*
     * Precompute an overly pessimistic guess at the number of arguments
     * in the command line by counting non-space spans.
     */

    size = 2;
    for (p = cmdLine; *p != '\0'; p++) {
	if ((*p == ' ') || (*p == '\t')) {	/* INTL: ISO space. */
	    size++;
	    while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */
		p++;
	    }
	    if (*p == '\0') {
		break;
	    }
	}
    }
    argSpace = (char *) ckalloc(
	    (unsigned) (size * sizeof(char *) + strlen(cmdLine) + 1));
    argv = (char **) argSpace;
    argSpace += size * sizeof(char *);
    size--;

    p = cmdLine;
    for (argc = 0; argc < size; argc++) {
	argv[argc] = arg = argSpace;
	while ((*p == ' ') || (*p == '\t')) {	/* INTL: ISO space. */
	    p++;
	}
	if (*p == '\0') {
	    break;
	}

	inquote = 0;
	slashes = 0;
	while (1) {
	    copy = 1;
	    while (*p == '\\') {
		slashes++;
		p++;
	    }
	    if (*p == '"') {
		if ((slashes & 1) == 0) {
		    copy = 0;
		    if ((inquote) && (p[1] == '"')) {
			p++;
			copy = 1;
		    } else {
			inquote = !inquote;
		    }
                }
                slashes >>= 1;
            }

            while (slashes) {
		*arg = '\\';
		arg++;
		slashes--;
	    }

	    if ((*p == '\0')
		    || (!inquote && ((*p == ' ') || (*p == '\t')))) { /* INTL: ISO space. */
		break;
	    }
	    if (copy != 0) {
		*arg = *p;
		arg++;
	    }
	    p++;
        }
	*arg = '\0';
	argSpace = arg + 1;
    }
    argv[argc] = NULL;

    *argcPtr = argc;
    *argvPtr = argv;
}

/*
 *----------------------------------------------------------------------
 *
 * asyncExit --
 *
 * 	The AsyncProc for the exitToken.
 *
 * Results:
 * 	doesn't actually return.
 *
 * Side effects:
 * 	tclsh cleanly exits.
 *
 *----------------------------------------------------------------------
 */

int
asyncExit (ClientData clientData, Tcl_Interp *interp, int code)



{
    Tcl_Exit((int)exitErrorCode);

    /* NOTREACHED */
    return code;
}








|

<
<
<
<
<









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


















|
>
>
>







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
 *	Frees the saved argv and deletes the async exit handler.
 *
 *----------------------------------------------------------------------
 */

static void
AppInitExitHandler(
    ClientData clientData)	/* Not Used. */
{





    if (exitToken != NULL) {
        /*
         * This should be safe to do even if we
         * are in an async exit right now.
         */
        Tcl_AsyncDelete(exitToken);
        exitToken = NULL;
    }
}






















































































































/*
 *----------------------------------------------------------------------
 *
 * asyncExit --
 *
 * 	The AsyncProc for the exitToken.
 *
 * Results:
 * 	doesn't actually return.
 *
 * Side effects:
 * 	tclsh cleanly exits.
 *
 *----------------------------------------------------------------------
 */

int
asyncExit (
    ClientData clientData,	/* Not Used. */
    Tcl_Interp *interp,		/* interp in context, if any. */
    int code)			/* result of last command, if any. */
{
    Tcl_Exit((int)exitErrorCode);

    /* NOTREACHED */
    return code;
}

418
419
420
421
422
423
424
425
426

427
428
429
430
431
432
433
 *	Effects the way the app exits from a signal. This is an
 *	operating system supplied thread and unsafe to call ANY
 *	Tcl commands except for Tcl_AsyncMark.
 *
 *----------------------------------------------------------------------
 */

BOOL __stdcall
sigHandler(DWORD fdwCtrlType)

{
    HANDLE hStdIn;

    if (!exitToken) {
	/* Async token must have been destroyed, punt gracefully. */
	return FALSE;
    }







|
|
>







285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
 *	Effects the way the app exits from a signal. This is an
 *	operating system supplied thread and unsafe to call ANY
 *	Tcl commands except for Tcl_AsyncMark.
 *
 *----------------------------------------------------------------------
 */

BOOL WINAPI
sigHandler(
    DWORD fdwCtrlType)	    /* One of the CTRL_*_EVENT constants. */
{
    HANDLE hStdIn;

    if (!exitToken) {
	/* Async token must have been destroyed, punt gracefully. */
	return FALSE;
    }
446
447
448
449
450
451
452
453
454
455
     * the attention of the interpreter.
     */
    hStdIn = GetStdHandle(STD_INPUT_HANDLE);
    if (hStdIn) {
	CloseHandle(hStdIn);
    }

    /* indicate to the OS not to call the default terminator */
    return TRUE;
}







|


314
315
316
317
318
319
320
321
322
323
     * the attention of the interpreter.
     */
    hStdIn = GetStdHandle(STD_INPUT_HANDLE);
    if (hStdIn) {
	CloseHandle(hStdIn);
    }

    /* indicate to the OS not to call the default terminator. */
    return TRUE;
}
Changes to win/tclWin32Dll.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclWin32Dll.c --
 *
 *	This file contains the DLL entry point.
 *
 * Copyright (c) 1995-1996 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 Scriptics Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWin32Dll.c,v 1.25.2.2 2003/10/16 02:28:04 dgp Exp $
 */

#include "tclWinInt.h"

/*
 * The following data structures are used when loading the thunking 
 * library for execing child processes under Win32s.











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclWin32Dll.c --
 *
 *	This file contains the DLL entry point.
 *
 * Copyright (c) 1995-1996 Sun Microsystems, Inc.
 * Copyright (c) 1998-2000 Scriptics Corporation.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWin32Dll.c,v 1.25.2.3 2004/02/07 05:48:12 dgp Exp $
 */

#include "tclWinInt.h"

/*
 * The following data structures are used when loading the thunking 
 * library for execing child processes under Win32s.
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
 *	initializing various dynamically loaded libraries.
 *
 * Results:
 *	TRUE on sucess, FALSE on failure.
 *
 * Side effects:
 *	Establishes 32-to-16 bit thunk and initializes sockets library.



 *
 *----------------------------------------------------------------------
 */
BOOL APIENTRY
DllMain(hInst, reason, reserved)
    HINSTANCE hInst;		/* Library instance handle. */
    DWORD reason;		/* Reason this function is being called. */
    LPVOID reserved;		/* Not used. */
{
    switch (reason) {
    case DLL_PROCESS_ATTACH:
	TclWinInit(hInst);
	return TRUE;

    case DLL_PROCESS_DETACH:















	if (hInst == hInstance) {








	    Tcl_Finalize();














	}





















	break;
    }

    return TRUE; 
}



















#endif /* !STATIC_BUILD */
#endif /* __WIN32__ */

/*
 *----------------------------------------------------------------------
 *
 * TclWinGetTclInstance --







>
>
>















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






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







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
 *	initializing various dynamically loaded libraries.
 *
 * Results:
 *	TRUE on sucess, FALSE on failure.
 *
 * Side effects:
 *	Establishes 32-to-16 bit thunk and initializes sockets library.
 *	This might call some sycronization functions, but MSDN
 *	documentation states: "Waiting on synchronization objects in
 *	DllMain can cause a deadlock."
 *
 *----------------------------------------------------------------------
 */
BOOL APIENTRY
DllMain(hInst, reason, reserved)
    HINSTANCE hInst;		/* Library instance handle. */
    DWORD reason;		/* Reason this function is being called. */
    LPVOID reserved;		/* Not used. */
{
    switch (reason) {
    case DLL_PROCESS_ATTACH:
	TclWinInit(hInst);
	return TRUE;

    case DLL_PROCESS_DETACH:
	/*
	 * Protect the call to Tcl_Finalize.  The OS could be unloading
	 * us from an exception handler and the state of the stack might
	 * be unstable.
	 */
#ifdef HAVE_NO_SEH
# ifdef TCL_MEM_DEBUG
    __asm__ __volatile__ (
            "movl %%esp,  %0" "\n\t"
            "movl %%ebp,  %1" "\n\t"
            "movl %%fs:0, %2" "\n\t"
            : "=m"(INITIAL_ESP),
              "=m"(INITIAL_EBP),
              "=r"(INITIAL_HANDLER) );
# endif /* TCL_MEM_DEBUG */

    __asm__ __volatile__ (
            "pushl %ebp" "\n\t"
            "pushl $__except_dllmain_detach_handler" "\n\t"
            "pushl %fs:0" "\n\t"
            "movl  %esp, %fs:0");
#else
	__try {
#endif /* HAVE_NO_SEH */
  	    Tcl_Finalize();
#ifdef HAVE_NO_SEH
    __asm__ __volatile__ (
            "jmp  dllmain_detach_pop" "\n"
        "dllmain_detach_reentry:" "\n\t"
            "movl %%fs:0, %%eax" "\n\t"
            "movl 0x8(%%eax), %%esp" "\n\t"
            "movl 0x8(%%esp), %%ebp" "\n"
        "dllmain_detach_pop:" "\n\t"
            "movl (%%esp), %%eax" "\n\t"
            "movl %%eax, %%fs:0" "\n\t"
            "add  $12, %%esp" "\n\t"
            :
            :
            : "%eax");

# ifdef TCL_MEM_DEBUG
    __asm__ __volatile__ (
            "movl  %%esp,  %0" "\n\t"
            "movl  %%ebp,  %1" "\n\t"
            "movl  %%fs:0, %2" "\n\t"
            : "=m"(RESTORED_ESP),
              "=m"(RESTORED_EBP),
              "=r"(RESTORED_HANDLER) );

    if (INITIAL_ESP != RESTORED_ESP)
        Tcl_Panic("ESP restored incorrectly");
    if (INITIAL_EBP != RESTORED_EBP)
        Tcl_Panic("EBP restored incorrectly");
    if (INITIAL_HANDLER != RESTORED_HANDLER)
        Tcl_Panic("HANDLER restored incorrectly");
# endif /* TCL_MEM_DEBUG */
#else
	} __except (EXCEPTION_EXECUTE_HANDLER) {
	    /* empty handler body. */
	}
#endif /* HAVE_NO_SEH */
	break;
    }

    return TRUE; 
}

#ifdef HAVE_NO_SEH
static
__attribute__ ((cdecl))
EXCEPTION_DISPOSITION
_except_dllmain_detach_handler(
    struct _EXCEPTION_RECORD *ExceptionRecord,
    void *EstablisherFrame,
    struct _CONTEXT *ContextRecord,
    void *DispatcherContext)
{
    __asm__ __volatile__ (
            "jmp dllmain_detach_reentry");
    /* Nuke compiler warning about unused static function */
    _except_dllmain_detach_handler(NULL, NULL, NULL, NULL);
    return 0; /* Function does not return */
}
#endif /* HAVE_NO_SEH */

#endif /* !STATIC_BUILD */
#endif /* __WIN32__ */

/*
 *----------------------------------------------------------------------
 *
 * TclWinGetTclInstance --
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324

    /*
     * We no longer support Win32s, so just in case someone manages to
     * get a runtime there, make sure they know that.
     */

    if (platformId == VER_PLATFORM_WIN32s) {
	panic("Win32s is not a supported platform");	
    }

    tclWinProcs = &asciiProcs;
}

/*
 *----------------------------------------------------------------------







|







389
390
391
392
393
394
395
396
397
398
399
400
401
402
403

    /*
     * We no longer support Win32s, so just in case someone manages to
     * get a runtime there, make sure they know that.
     */

    if (platformId == VER_PLATFORM_WIN32s) {
	Tcl_Panic("Win32s is not a supported platform");	
    }

    tclWinProcs = &asciiProcs;
}

/*
 *----------------------------------------------------------------------
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
            "movl  %%ebp,  %1" "\n\t"
            "movl  %%fs:0, %2" "\n\t"
            : "=m"(RESTORED_ESP),
              "=m"(RESTORED_EBP),
              "=r"(RESTORED_HANDLER) );

    if (INITIAL_ESP != RESTORED_ESP)
        panic("ESP restored incorrectly");
    if (INITIAL_EBP != RESTORED_EBP)
        panic("EBP restored incorrectly");
    if (INITIAL_HANDLER != RESTORED_HANDLER)
        panic("HANDLER restored incorrectly");
# endif /* TCL_MEM_DEBUG */
#else
    } __except (EXCEPTION_EXECUTE_HANDLER) {}
#endif /* HAVE_NO_SEH */

    /*
     * Avoid using control flow statements in the SEH guarded block!







|

|

|







537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
            "movl  %%ebp,  %1" "\n\t"
            "movl  %%fs:0, %2" "\n\t"
            : "=m"(RESTORED_ESP),
              "=m"(RESTORED_EBP),
              "=r"(RESTORED_HANDLER) );

    if (INITIAL_ESP != RESTORED_ESP)
        Tcl_Panic("ESP restored incorrectly");
    if (INITIAL_EBP != RESTORED_EBP)
        Tcl_Panic("EBP restored incorrectly");
    if (INITIAL_HANDLER != RESTORED_HANDLER)
        Tcl_Panic("HANDLER restored incorrectly");
# endif /* TCL_MEM_DEBUG */
#else
    } __except (EXCEPTION_EXECUTE_HANDLER) {}
#endif /* HAVE_NO_SEH */

    /*
     * Avoid using control flow statements in the SEH guarded block!
565
566
567
568
569
570
571




572
573
574
575
576
577
578
		  (HANDLE (WINAPI *)(CONST TCHAR*, UINT,
		  LPVOID, UINT, LPVOID, DWORD)) GetProcAddress(hInstance, 
		  "FindFirstFileExW");
	        tclWinProcs->getVolumeNameForVMPProc = 
		  (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*, 
		  DWORD)) GetProcAddress(hInstance, 
		  "GetVolumeNameForVolumeMountPointW");




		FreeLibrary(hInstance);
	    }
	    hInstance = LoadLibraryA("advapi32");
	    if (hInstance != NULL) {
		tclWinProcs->getFileSecurityProc = (BOOL (WINAPI *)(
		  LPCTSTR lpFileName, 
		  SECURITY_INFORMATION RequestedInformation,







>
>
>
>







644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
		  (HANDLE (WINAPI *)(CONST TCHAR*, UINT,
		  LPVOID, UINT, LPVOID, DWORD)) GetProcAddress(hInstance, 
		  "FindFirstFileExW");
	        tclWinProcs->getVolumeNameForVMPProc = 
		  (BOOL (WINAPI *)(CONST TCHAR*, TCHAR*, 
		  DWORD)) GetProcAddress(hInstance, 
		  "GetVolumeNameForVolumeMountPointW");
		tclWinProcs->getLongPathNameProc = 
		  (DWORD (WINAPI *)(CONST TCHAR*, TCHAR*, 
		  DWORD)) GetProcAddress(hInstance, 
		  "GetLongPathNameW");
		FreeLibrary(hInstance);
	    }
	    hInstance = LoadLibraryA("advapi32");
	    if (hInstance != NULL) {
		tclWinProcs->getFileSecurityProc = (BOOL (WINAPI *)(
		  LPCTSTR lpFileName, 
		  SECURITY_INFORMATION RequestedInformation,
613
614
615
616
617
618
619

620
621
622
623
624
625
626
		  (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS, 
		  LPVOID)) GetProcAddress(hInstance, "GetFileAttributesExA");
		tclWinProcs->createHardLinkProc = 
		  (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*, 
		  LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance, 
		  "CreateHardLinkA");
		tclWinProcs->findFirstFileExProc = NULL;

		/*
		 * The 'findFirstFileExProc' function exists on some
		 * of 95/98/ME, but it seems not to work as anticipated.
		 * Therefore we don't set this function pointer.  The
		 * relevant code will fall back on a slower approach
		 * using the normal findFirstFileProc.
		 * 







>







696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
		  (BOOL (WINAPI *)(CONST TCHAR *, GET_FILEEX_INFO_LEVELS, 
		  LPVOID)) GetProcAddress(hInstance, "GetFileAttributesExA");
		tclWinProcs->createHardLinkProc = 
		  (BOOL (WINAPI *)(CONST TCHAR *, CONST TCHAR*, 
		  LPSECURITY_ATTRIBUTES)) GetProcAddress(hInstance, 
		  "CreateHardLinkA");
		tclWinProcs->findFirstFileExProc = NULL;
		tclWinProcs->getLongPathNameProc = NULL;
		/*
		 * The 'findFirstFileExProc' function exists on some
		 * of 95/98/ME, but it seems not to work as anticipated.
		 * Therefore we don't set this function pointer.  The
		 * relevant code will fall back on a slower approach
		 * using the normal findFirstFileProc.
		 * 
Changes to win/tclWinChan.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclWinChan.c
 *
 *	Channel drivers for Windows channels based on files, command
 *	pipes and TCP sockets.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWinChan.c,v 1.30 2003/01/26 05:59:38 mdejong Exp $
 */

#include "tclWinInt.h"
#include "tclIO.h"

/*
 * State flags used in the info structures below.











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclWinChan.c
 *
 *	Channel drivers for Windows channels based on files, command
 *	pipes and TCP sockets.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWinChan.c,v 1.30.4.1 2004/02/07 05:48:12 dgp Exp $
 */

#include "tclWinInt.h"
#include "tclIO.h"

/*
 * State flags used in the info structures below.
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
    ClientData instanceData;	/* File state. */
    long offset;		/* Offset to seek to. */
    int mode;			/* Relative to where should we seek? */
    int *errorCodePtr;		/* To store error code. */
{
    FileInfo *infoPtr = (FileInfo *) instanceData;
    DWORD moveMethod;
    DWORD newPos, newPosHigh;
    DWORD oldPos, oldPosHigh;

    *errorCodePtr = 0;
    if (mode == SEEK_SET) {
        moveMethod = FILE_BEGIN;
    } else if (mode == SEEK_CUR) {
        moveMethod = FILE_CURRENT;
    } else {
        moveMethod = FILE_END;
    }

    /*
     * Save our current place in case we need to roll-back the seek.
     */
    oldPosHigh = (DWORD)0;
    oldPos = SetFilePointer(infoPtr->handle, (LONG)0, &oldPosHigh,
	    FILE_CURRENT);
    if (oldPos == INVALID_SET_FILE_POINTER) {
	DWORD winError = GetLastError();
	if (winError != NO_ERROR) {
	    TclWinConvertError(winError);
	    *errorCodePtr = errno;
	    return -1;
	}
    }

    newPosHigh = (DWORD)(offset < 0 ? -1 : 0);
    newPos = SetFilePointer(infoPtr->handle, (LONG) offset, &newPosHigh,
			    moveMethod);
    if (newPos == INVALID_SET_FILE_POINTER) {
	DWORD winError = GetLastError();
	if (winError != NO_ERROR) {
	    TclWinConvertError(winError);
	    *errorCodePtr = errno;
	    return -1;
	}
    }

    /*
     * Check for expressability in our return type, and roll-back otherwise.
     */
    if (newPosHigh != 0) {
	*errorCodePtr = EOVERFLOW;
	SetFilePointer(infoPtr->handle, (LONG)oldPos, &oldPosHigh, FILE_BEGIN);
	return -1;
    }
    return (int) newPos;
}

/*
 *----------------------------------------------------------------------







|
|













|
|










|
|















|







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
    ClientData instanceData;	/* File state. */
    long offset;		/* Offset to seek to. */
    int mode;			/* Relative to where should we seek? */
    int *errorCodePtr;		/* To store error code. */
{
    FileInfo *infoPtr = (FileInfo *) instanceData;
    DWORD moveMethod;
    LONG newPos, newPosHigh;
    LONG oldPos, oldPosHigh;

    *errorCodePtr = 0;
    if (mode == SEEK_SET) {
        moveMethod = FILE_BEGIN;
    } else if (mode == SEEK_CUR) {
        moveMethod = FILE_CURRENT;
    } else {
        moveMethod = FILE_END;
    }

    /*
     * Save our current place in case we need to roll-back the seek.
     */
    oldPosHigh = 0;
    oldPos = SetFilePointer(infoPtr->handle, 0, &oldPosHigh,
	    FILE_CURRENT);
    if (oldPos == INVALID_SET_FILE_POINTER) {
	DWORD winError = GetLastError();
	if (winError != NO_ERROR) {
	    TclWinConvertError(winError);
	    *errorCodePtr = errno;
	    return -1;
	}
    }

    newPosHigh = (offset < 0 ? -1 : 0);
    newPos = SetFilePointer(infoPtr->handle, offset, &newPosHigh,
			    moveMethod);
    if (newPos == INVALID_SET_FILE_POINTER) {
	DWORD winError = GetLastError();
	if (winError != NO_ERROR) {
	    TclWinConvertError(winError);
	    *errorCodePtr = errno;
	    return -1;
	}
    }

    /*
     * Check for expressability in our return type, and roll-back otherwise.
     */
    if (newPosHigh != 0) {
	*errorCodePtr = EOVERFLOW;
	SetFilePointer(infoPtr->handle, oldPos, &oldPosHigh, FILE_BEGIN);
	return -1;
    }
    return (int) newPos;
}

/*
 *----------------------------------------------------------------------
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
    ClientData instanceData;	/* File state. */
    Tcl_WideInt offset;		/* Offset to seek to. */
    int mode;			/* Relative to where should we seek? */
    int *errorCodePtr;		/* To store error code. */
{
    FileInfo *infoPtr = (FileInfo *) instanceData;
    DWORD moveMethod;
    DWORD newPos, newPosHigh;

    *errorCodePtr = 0;
    if (mode == SEEK_SET) {
        moveMethod = FILE_BEGIN;
    } else if (mode == SEEK_CUR) {
        moveMethod = FILE_CURRENT;
    } else {
        moveMethod = FILE_END;
    }

    newPosHigh = (DWORD)(offset >> 32);
    newPos = SetFilePointer(infoPtr->handle, (LONG) offset, &newPosHigh,
			    moveMethod);
    if (newPos == INVALID_SET_FILE_POINTER) {
	DWORD winError = GetLastError();
	if (winError != NO_ERROR) {
	    TclWinConvertError(winError);
	    *errorCodePtr = errno;
	    return -1;
	}
    }
    return ((Tcl_WideInt) newPos) | (((Tcl_WideInt) newPosHigh) << 32);
}

/*
 *----------------------------------------------------------------------
 *
 * FileInputProc --
 *







|










|
|
|








|







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
    ClientData instanceData;	/* File state. */
    Tcl_WideInt offset;		/* Offset to seek to. */
    int mode;			/* Relative to where should we seek? */
    int *errorCodePtr;		/* To store error code. */
{
    FileInfo *infoPtr = (FileInfo *) instanceData;
    DWORD moveMethod;
    LONG newPos, newPosHigh;

    *errorCodePtr = 0;
    if (mode == SEEK_SET) {
        moveMethod = FILE_BEGIN;
    } else if (mode == SEEK_CUR) {
        moveMethod = FILE_CURRENT;
    } else {
        moveMethod = FILE_END;
    }

    newPosHigh = Tcl_WideAsLong(offset >> 32);
    newPos = SetFilePointer(infoPtr->handle, Tcl_WideAsLong(offset),
	    &newPosHigh, moveMethod);
    if (newPos == INVALID_SET_FILE_POINTER) {
	DWORD winError = GetLastError();
	if (winError != NO_ERROR) {
	    TclWinConvertError(winError);
	    *errorCodePtr = errno;
	    return -1;
	}
    }
    return (Tcl_LongAsWide(newPos) | (Tcl_LongAsWide(newPosHigh) << 32));
}

/*
 *----------------------------------------------------------------------
 *
 * FileInputProc --
 *
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
	    channelPermissions = TCL_WRITABLE;
	    break;
	case O_RDWR:
	    accessMode = (GENERIC_READ | GENERIC_WRITE);
	    channelPermissions = (TCL_READABLE | TCL_WRITABLE);
	    break;
	default:
	    panic("TclpOpenFileChannel: invalid mode value");
	    break;
    }

    /*
     * Map the creation flags to the NT create mode.
     */








|







775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
	    channelPermissions = TCL_WRITABLE;
	    break;
	case O_RDWR:
	    accessMode = (GENERIC_READ | GENERIC_WRITE);
	    channelPermissions = (TCL_READABLE | TCL_WRITABLE);
	    break;
	default:
	    Tcl_Panic("TclpOpenFileChannel: invalid mode value");
	    break;
    }

    /*
     * Map the creation flags to the NT create mode.
     */

1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
            "movl  %%ebp,  %1" "\n\t"
            "movl  %%fs:0, %2" "\n\t"
            : "=m"(RESTORED_ESP),
              "=m"(RESTORED_EBP),
              "=r"(RESTORED_HANDLER) );

    if (INITIAL_ESP != RESTORED_ESP)
        panic("ESP restored incorrectly");
    if (INITIAL_EBP != RESTORED_EBP)
        panic("EBP restored incorrectly");
    if (INITIAL_HANDLER != RESTORED_HANDLER)
        panic("HANDLER restored incorrectly");
# endif /* TCL_MEM_DEBUG */

        if (result)
            return NULL;
#else
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {







|

|

|







1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
            "movl  %%ebp,  %1" "\n\t"
            "movl  %%fs:0, %2" "\n\t"
            : "=m"(RESTORED_ESP),
              "=m"(RESTORED_EBP),
              "=r"(RESTORED_HANDLER) );

    if (INITIAL_ESP != RESTORED_ESP)
        Tcl_Panic("ESP restored incorrectly");
    if (INITIAL_EBP != RESTORED_EBP)
        Tcl_Panic("EBP restored incorrectly");
    if (INITIAL_HANDLER != RESTORED_HANDLER)
        Tcl_Panic("HANDLER restored incorrectly");
# endif /* TCL_MEM_DEBUG */

        if (result)
            return NULL;
#else
	}
	__except (EXCEPTION_EXECUTE_HANDLER) {
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
	    break;
	case TCL_STDERR:
	    handleId = STD_ERROR_HANDLE;
	    mode = TCL_WRITABLE;
	    bufMode = "none";
	    break;
	default:
	    panic("TclGetDefaultStdChannel: Unexpected channel type");
	    break;
    }

    handle = GetStdHandle(handleId);

    /*
     * Note that we need to check for 0 because Windows may return 0 if this







|







1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
	    break;
	case TCL_STDERR:
	    handleId = STD_ERROR_HANDLE;
	    mode = TCL_WRITABLE;
	    bufMode = "none";
	    break;
	default:
	    Tcl_Panic("TclGetDefaultStdChannel: Unexpected channel type");
	    break;
    }

    handle = GetStdHandle(handleId);

    /*
     * Note that we need to check for 0 because Windows may return 0 if this
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400

    /*
     * This could happen if the channel was created in one thread
     * and then moved to another without updating the thread
     * local data in each thread.
     */

    if (!removed)
        panic("file info ptr not on thread channel list");

}

/*
 *----------------------------------------------------------------------
 *
 * TclpSpliceFileChannel --
 *







|
|
|







1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400

    /*
     * This could happen if the channel was created in one thread
     * and then moved to another without updating the thread
     * local data in each thread.
     */

    if (!removed) {
        Tcl_Panic("file info ptr not on thread channel list");
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TclpSpliceFileChannel --
 *
Changes to win/tclWinDde.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclWinDde.c --
 *
 *	This file provides procedures that implement the "send"
 *	command, allowing commands to be passed from interpreter
 *	to interpreter.
 *
 * Copyright (c) 1997 by Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWinDde.c,v 1.15.2.1 2003/06/24 17:27:42 dgp Exp $
 */

#include "tclPort.h"
#include <dde.h>
#include <ddeml.h>
#include <tchar.h>
/*












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclWinDde.c --
 *
 *	This file provides procedures that implement the "send"
 *	command, allowing commands to be passed from interpreter
 *	to interpreter.
 *
 * Copyright (c) 1997 by Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWinDde.c,v 1.15.2.2 2004/02/07 05:48:12 dgp Exp $
 */

#include "tclPort.h"
#include <dde.h>
#include <ddeml.h>
#include <tchar.h>
/*
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
 * The Mutex ddeMutex guards access to the ddeInstance.
 */
static HSZ ddeServiceGlobal = 0;
static DWORD ddeInstance;       /* The application instance handle given
				 * to us by DdeInitialize. */
static int ddeIsServer = 0;

#define TCL_DDE_VERSION "1.2.5"
#define TCL_DDE_PACKAGE_NAME "dde"
#define TCL_DDE_SERVICE_NAME "TclEval"

TCL_DECLARE_MUTEX(ddeMutex)

/*
 * Forward declarations for procedures defined later in this file.







|







67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
 * The Mutex ddeMutex guards access to the ddeInstance.
 */
static HSZ ddeServiceGlobal = 0;
static DWORD ddeInstance;       /* The application instance handle given
				 * to us by DdeInitialize. */
static int ddeIsServer = 0;

#define TCL_DDE_VERSION "1.3"
#define TCL_DDE_PACKAGE_NAME "dde"
#define TCL_DDE_SERVICE_NAME "TclEval"

TCL_DECLARE_MUTEX(ddeMutex)

/*
 * Forward declarations for procedures defined later in this file.
Changes to win/tclWinFCmd.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

25
26
27
28
29
30
31
/*
 * tclWinFCmd.c
 *
 *      This file implements the Windows specific portion of file manipulation 
 *      subcommands of the "file" command. 
 *
 * Copyright (c) 1996-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.
 *
 * RCS: @(#) $Id: tclWinFCmd.c,v 1.35.4.2 2003/10/16 02:28:04 dgp Exp $
 */

#include "tclWinInt.h"

/*
 * The following constants specify the type of callback when
 * TraverseWinTree() calls the traverseProc()
 */

#define DOTREE_PRED   1     /* pre-order directory  */
#define DOTREE_POSTD  2     /* post-order directory */
#define DOTREE_F      3     /* regular file */


/*
 * Callbacks for file attributes code.
 */

static int		GetWinFileAttributes _ANSI_ARGS_((Tcl_Interp *interp,
			    int objIndex, Tcl_Obj *fileName,











|












>







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
/*
 * tclWinFCmd.c
 *
 *      This file implements the Windows specific portion of file manipulation 
 *      subcommands of the "file" command. 
 *
 * Copyright (c) 1996-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.
 *
 * RCS: @(#) $Id: tclWinFCmd.c,v 1.35.4.3 2004/02/07 05:48:12 dgp Exp $
 */

#include "tclWinInt.h"

/*
 * The following constants specify the type of callback when
 * TraverseWinTree() calls the traverseProc()
 */

#define DOTREE_PRED   1     /* pre-order directory  */
#define DOTREE_POSTD  2     /* post-order directory */
#define DOTREE_F      3     /* regular file */
#define DOTREE_LINK   4     /* symbolic link */

/*
 * Callbacks for file attributes code.
 */

static int		GetWinFileAttributes _ANSI_ARGS_((Tcl_Interp *interp,
			    int objIndex, Tcl_Obj *fileName,
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
            "movl  %%ebp,  %1" "\n\t"
            "movl  %%fs:0, %2" "\n\t"
            : "=m"(RESTORED_ESP),
              "=m"(RESTORED_EBP),
              "=r"(RESTORED_HANDLER) );

    if (INITIAL_ESP != RESTORED_ESP)
        panic("ESP restored incorrectly");
    if (INITIAL_EBP != RESTORED_EBP)
        panic("EBP restored incorrectly");
    if (INITIAL_HANDLER != RESTORED_HANDLER)
        panic("HANDLER restored incorrectly");
# endif /* TCL_MEM_DEBUG */
#else
    } __except (EXCEPTION_EXECUTE_HANDLER) {}
#endif /* HAVE_NO_SEH */

    /*
     * Avoid using control flow statements in the SEH guarded block!







|

|

|







234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
            "movl  %%ebp,  %1" "\n\t"
            "movl  %%fs:0, %2" "\n\t"
            : "=m"(RESTORED_ESP),
              "=m"(RESTORED_EBP),
              "=r"(RESTORED_HANDLER) );

    if (INITIAL_ESP != RESTORED_ESP)
        Tcl_Panic("ESP restored incorrectly");
    if (INITIAL_EBP != RESTORED_EBP)
        Tcl_Panic("EBP restored incorrectly");
    if (INITIAL_HANDLER != RESTORED_HANDLER)
        Tcl_Panic("HANDLER restored incorrectly");
# endif /* TCL_MEM_DEBUG */
#else
    } __except (EXCEPTION_EXECUTE_HANDLER) {}
#endif /* HAVE_NO_SEH */

    /*
     * Avoid using control flow statements in the SEH guarded block!
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
            "movl  %%ebp,  %1" "\n\t"
            "movl  %%fs:0, %2" "\n\t"
            : "=m"(RESTORED_ESP),
              "=m"(RESTORED_EBP),
              "=r"(RESTORED_HANDLER) );

    if (INITIAL_ESP != RESTORED_ESP)
        panic("ESP restored incorrectly");
    if (INITIAL_EBP != RESTORED_EBP)
        panic("EBP restored incorrectly");
    if (INITIAL_HANDLER != RESTORED_HANDLER)
        panic("HANDLER restored incorrectly");
# endif /* TCL_MEM_DEBUG */
#else
    } __except (EXCEPTION_EXECUTE_HANDLER) {}
#endif /* HAVE_NO_SEH */

    /*
     * Avoid using control flow statements in the SEH guarded block!







|

|

|







596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
            "movl  %%ebp,  %1" "\n\t"
            "movl  %%fs:0, %2" "\n\t"
            : "=m"(RESTORED_ESP),
              "=m"(RESTORED_EBP),
              "=r"(RESTORED_HANDLER) );

    if (INITIAL_ESP != RESTORED_ESP)
        Tcl_Panic("ESP restored incorrectly");
    if (INITIAL_EBP != RESTORED_EBP)
        Tcl_Panic("EBP restored incorrectly");
    if (INITIAL_HANDLER != RESTORED_HANDLER)
        Tcl_Panic("HANDLER restored incorrectly");
# endif /* TCL_MEM_DEBUG */
#else
    } __except (EXCEPTION_EXECUTE_HANDLER) {}
#endif /* HAVE_NO_SEH */

    /*
     * Avoid using control flow statements in the SEH guarded block!
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
    int ignoreError,		/* If non-zero, don't initialize the
                  		 * errorPtr under some circumstances
                  		 * on return. */
    Tcl_DString *errorPtr)	/* If non-NULL, uninitialized or free
				 * DString filled with UTF-8 name of file
				 * causing error. */
{

    /*
     * The RemoveDirectory API acts differently under Win95/98 and NT
     * WRT NULL and "". Avoid passing these values.
     */

    if (nativePath == NULL || nativePath[0] == '\0') {
	Tcl_SetErrno(ENOENT);
	goto end;
    }










    if ((*tclWinProcs->removeDirectoryProc)(nativePath) != FALSE) {
	return TCL_OK;
    }


    TclWinConvertError(GetLastError());

    if (Tcl_GetErrno() == EACCES) {
	DWORD attr = (*tclWinProcs->getFileAttributesProc)(nativePath);
	if (attr != 0xffffffff) {
	    if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
		/* 
		 * Windows 95 reports calling RemoveDirectory on a file as an 
		 * EACCES, not an ENOTDIR.
		 */
		







>










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



|







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
    int ignoreError,		/* If non-zero, don't initialize the
                  		 * errorPtr under some circumstances
                  		 * on return. */
    Tcl_DString *errorPtr)	/* If non-NULL, uninitialized or free
				 * DString filled with UTF-8 name of file
				 * causing error. */
{
    DWORD attr;
    /*
     * The RemoveDirectory API acts differently under Win95/98 and NT
     * WRT NULL and "". Avoid passing these values.
     */

    if (nativePath == NULL || nativePath[0] == '\0') {
	Tcl_SetErrno(ENOENT);
	goto end;
    }

    attr = (*tclWinProcs->getFileAttributesProc)(nativePath);

    if (attr & FILE_ATTRIBUTE_REPARSE_POINT) {
	/* It is a symbolic link -- remove it */
	if (TclWinSymLinkDelete(nativePath, 0) == 0) {
	    return TCL_OK;
	}
    } else {
	/* Ordinary directory */
	if ((*tclWinProcs->removeDirectoryProc)(nativePath) != FALSE) {
	    return TCL_OK;
	}
    }
    
    TclWinConvertError(GetLastError());

    if (Tcl_GetErrno() == EACCES) {
	attr = (*tclWinProcs->getFileAttributesProc)(nativePath);
	if (attr != 0xffffffff) {
	    if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
		/* 
		 * Windows 95 reports calling RemoveDirectory on a file as an 
		 * EACCES, not an ENOTDIR.
		 */
		
1017
1018
1019
1020
1021
1022
1023

1024
1025
1026
1027
1028
1029
1030
			attr | FILE_ATTRIBUTE_READONLY);
	    }

	    /* 
	     * Windows 95 and Win32s report removing a non-empty directory 
	     * as EACCES, not EEXIST.  If the directory is not empty,
	     * change errno so caller knows what's going on.

	     */

	    if (TclWinGetPlatformId() != VER_PLATFORM_WIN32_NT) {
		CONST char *path, *find;
		HANDLE handle;
		WIN32_FIND_DATAA data;
		Tcl_DString buffer;







>







1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
			attr | FILE_ATTRIBUTE_READONLY);
	    }

	    /* 
	     * Windows 95 and Win32s report removing a non-empty directory 
	     * as EACCES, not EEXIST.  If the directory is not empty,
	     * change errno so caller knows what's going on.

	     */

	    if (TclWinGetPlatformId() != VER_PLATFORM_WIN32_NT) {
		CONST char *path, *find;
		HANDLE handle;
		WIN32_FIND_DATAA data;
		Tcl_DString buffer;
1162
1163
1164
1165
1166
1167
1168










1169
1170
1171
1172
1173
1174
1175
    
    oldSourceLen = Tcl_DStringLength(sourcePtr);
    sourceAttr = (*tclWinProcs->getFileAttributesProc)(nativeSource);
    if (sourceAttr == 0xffffffff) {
	nativeErrfile = nativeSource;
	goto end;
    }










    if ((sourceAttr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
	/*
	 * Process the regular file
	 */

	return (*traverseProc)(nativeSource, nativeTarget, DOTREE_F, errorPtr);
    }







>
>
>
>
>
>
>
>
>
>







1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
    
    oldSourceLen = Tcl_DStringLength(sourcePtr);
    sourceAttr = (*tclWinProcs->getFileAttributesProc)(nativeSource);
    if (sourceAttr == 0xffffffff) {
	nativeErrfile = nativeSource;
	goto end;
    }
    
    if (sourceAttr & FILE_ATTRIBUTE_REPARSE_POINT) {
	/*
	 * Process the symbolic link
	 */

	return (*traverseProc)(nativeSource, nativeTarget, 
			       DOTREE_LINK, errorPtr);
    }
    
    if ((sourceAttr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
	/*
	 * Process the regular file
	 */

	return (*traverseProc)(nativeSource, nativeTarget, DOTREE_F, errorPtr);
    }
1339
1340
1341
1342
1343
1344
1345






1346
1347
1348
1349
1350

1351
1352
1353
1354
1355
1356
1357
{
    switch (type) {
	case DOTREE_F: {
	    if (DoCopyFile(nativeSrc, nativeDst) == TCL_OK) {
		return TCL_OK;
	    }
	    break;






	}
	case DOTREE_PRED: {
	    if (DoCreateDirectory(nativeDst) == TCL_OK) {
		DWORD attr = (*tclWinProcs->getFileAttributesProc)(nativeSrc);
		if ((*tclWinProcs->setFileAttributesProc)(nativeDst, attr) != FALSE) {

		    return TCL_OK;
		}
		TclWinConvertError(GetLastError());
	    }
	    break;
	}
        case DOTREE_POSTD: {







>
>
>
>
>
>




|
>







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
{
    switch (type) {
	case DOTREE_F: {
	    if (DoCopyFile(nativeSrc, nativeDst) == TCL_OK) {
		return TCL_OK;
	    }
	    break;
	}
	case DOTREE_LINK: {
	    if (TclWinSymLinkCopyDirectory(nativeSrc, nativeDst) == TCL_OK) {
		return TCL_OK;
	    }
	    break;
	}
	case DOTREE_PRED: {
	    if (DoCreateDirectory(nativeDst) == TCL_OK) {
		DWORD attr = (*tclWinProcs->getFileAttributesProc)(nativeSrc);
		if ((*tclWinProcs->setFileAttributesProc)(nativeDst, attr) 
		  != FALSE) {
		    return TCL_OK;
		}
		TclWinConvertError(GetLastError());
	    }
	    break;
	}
        case DOTREE_POSTD: {
1401
1402
1403
1404
1405
1406
1407






1408
1409
1410
1411
1412
1413
1414
{
    switch (type) {
	case DOTREE_F: {
	    if (TclpDeleteFile(nativeSrc) == TCL_OK) {
		return TCL_OK;
	    }
	    break;






	}
	case DOTREE_PRED: {
	    return TCL_OK;
	}
	case DOTREE_POSTD: {
	    if (DoRemoveJustDirectory(nativeSrc, 0, NULL) == TCL_OK) {
		return TCL_OK;







>
>
>
>
>
>







1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
{
    switch (type) {
	case DOTREE_F: {
	    if (TclpDeleteFile(nativeSrc) == TCL_OK) {
		return TCL_OK;
	    }
	    break;
	}
	case DOTREE_LINK: {
	    if (DoRemoveJustDirectory(nativeSrc, 0, NULL) == TCL_OK) {
		return TCL_OK;
	    }
	    break;
	}
	case DOTREE_PRED: {
	    return TCL_OK;
	}
	case DOTREE_POSTD: {
	    if (DoRemoveJustDirectory(nativeSrc, 0, NULL) == TCL_OK) {
		return TCL_OK;
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
    int objIndex,		/* The index of the attribute. */
    Tcl_Obj *fileName,   	/* The name of the file. */
    int longShort,		/* 0 to short name, 1 to long name. */
    Tcl_Obj **attributePtrPtr)	/* A pointer to return the object with. */
{
    int pathc, i;
    Tcl_Obj *splitPath;
    int result = TCL_OK;

    splitPath = Tcl_FSSplitPath(fileName, &pathc);

    if (splitPath == NULL || pathc == 0) {
	if (interp != NULL) {
	    Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), 
		"could not read \"", Tcl_GetString(fileName),
		"\": no such file or directory", 
		(char *) NULL);
	}
	result = TCL_ERROR;
	goto cleanup;
    }
    







    for (i = 0; i < pathc; i++) {
	Tcl_Obj *elt;
	char *pathv;
	int pathLen;
	Tcl_ListObjIndex(NULL, splitPath, i, &elt);
	
	pathv = Tcl_GetStringFromObj(elt, &pathLen);







<


|







<



>
>
>
>
>
>
>







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
    int objIndex,		/* The index of the attribute. */
    Tcl_Obj *fileName,   	/* The name of the file. */
    int longShort,		/* 0 to short name, 1 to long name. */
    Tcl_Obj **attributePtrPtr)	/* A pointer to return the object with. */
{
    int pathc, i;
    Tcl_Obj *splitPath;


    splitPath = Tcl_FSSplitPath(fileName, &pathc);
    
    if (splitPath == NULL || pathc == 0) {
	if (interp != NULL) {
	    Tcl_AppendStringsToObj(Tcl_GetObjResult(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.
     */
    Tcl_IncrRefCount(splitPath);

    for (i = 0; i < pathc; i++) {
	Tcl_Obj *elt;
	char *pathv;
	int pathLen;
	Tcl_ListObjIndex(NULL, splitPath, i, &elt);
	
	pathv = Tcl_GetStringFromObj(elt, &pathLen);
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
	    }

	    if (handle == INVALID_HANDLE_VALUE) {
		Tcl_DStringFree(&ds);
		if (interp != NULL) {
		    StatError(interp, fileName);
		}
		result = TCL_ERROR;
		goto cleanup;
	    }
	    if (tclWinProcs->useWide) {
		nativeName = (TCHAR *) data.w.cAlternateFileName;
		if (longShort) {
		    if (data.w.cFileName[0] != '\0') {
			nativeName = (TCHAR *) data.w.cFileName;







<







1673
1674
1675
1676
1677
1678
1679

1680
1681
1682
1683
1684
1685
1686
	    }

	    if (handle == INVALID_HANDLE_VALUE) {
		Tcl_DStringFree(&ds);
		if (interp != NULL) {
		    StatError(interp, fileName);
		}

		goto cleanup;
	    }
	    if (tclWinProcs->useWide) {
		nativeName = (TCHAR *) data.w.cAlternateFileName;
		if (longShort) {
		    if (data.w.cFileName[0] != '\0') {
			nativeName = (TCHAR *) data.w.cFileName;
1689
1690
1691
1692
1693
1694
1695
1696














1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
	    Tcl_DStringFree(&ds);
	    Tcl_DStringFree(&dsTemp);
	    FindClose(handle);
	}
    }

    *attributePtrPtr = Tcl_FSJoinPath(splitPath, -1);















cleanup:
    if (splitPath != NULL) {
	Tcl_DecrRefCount(splitPath);
    }
  
    return result;
}

/*
 *----------------------------------------------------------------------
 *
 * GetWinFileLongName --
 *







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




|







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
	    Tcl_DStringFree(&ds);
	    Tcl_DStringFree(&dsTemp);
	    FindClose(handle);
	}
    }

    *attributePtrPtr = Tcl_FSJoinPath(splitPath, -1);
    
    if (splitPath != NULL) {
	/* 
	 * Unfortunately, the object we will return may have its only
	 * refCount as part of the list splitPath.  This means if
	 * we free splitPath, the object will disappear.  So, we
	 * have to be very careful here.  Unfortunately this means
	 * we must manipulate the object's refCount directly.
	 */
	Tcl_IncrRefCount(*attributePtrPtr);
	Tcl_DecrRefCount(splitPath);
	--(*attributePtrPtr)->refCount;
    }
    return TCL_OK;

  cleanup:
    if (splitPath != NULL) {
	Tcl_DecrRefCount(splitPath);
    }
  
    return TCL_ERROR;
}

/*
 *----------------------------------------------------------------------
 *
 * GetWinFileLongName --
 *
Changes to win/tclWinFile.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclWinFile.c --
 *
 *      This file contains temporary wrappers around UNIX file handling
 *      functions. These wrappers map the UNIX functions to Win32 HANDLE-style
 *      files, which can be manipulated through the Win32 console redirection
 *      interfaces.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclWinFile.c,v 1.50.2.4 2003/10/16 02:28:04 dgp Exp $
 */

//#define _WIN32_WINNT  0x0500

#include "tclWinInt.h"
#include <winioctl.h>
#include <sys/stat.h>













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* 
 * tclWinFile.c --
 *
 *      This file contains temporary wrappers around UNIX file handling
 *      functions. These wrappers map the UNIX functions to Win32 HANDLE-style
 *      files, which can be manipulated through the Win32 console redirection
 *      interfaces.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclWinFile.c,v 1.50.2.5 2004/02/07 05:48:12 dgp Exp $
 */

//#define _WIN32_WINNT  0x0500

#include "tclWinInt.h"
#include <winioctl.h>
#include <sys/stat.h>
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
    /* Make sure source file doesn't exist */
    attr = (*tclWinProcs->getFileAttributesProc)(LinkSource);
    if (attr != 0xffffffff) {
	Tcl_SetErrno(EEXIST);
	return -1;
    }

    /* Get the full path referenced by the directory */
    if (!(*tclWinProcs->getFullPathNameProc)(LinkSource, 
			  MAX_PATH, tempFileName, &tempFilePart)) {
	/* Invalid file */
	TclWinConvertError(GetLastError());
	return -1;
    }
    /* Check the target */







|







214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
    /* Make sure source file doesn't exist */
    attr = (*tclWinProcs->getFileAttributesProc)(LinkSource);
    if (attr != 0xffffffff) {
	Tcl_SetErrno(EEXIST);
	return -1;
    }

    /* Get the full path referenced by the source file/directory */
    if (!(*tclWinProcs->getFullPathNameProc)(LinkSource, 
			  MAX_PATH, tempFileName, &tempFilePart)) {
	/* Invalid file */
	TclWinConvertError(GetLastError());
	return -1;
    }
    /* Check the target */
738
739
740
741
742
743
744





745
746
747
748
749
750
751
    Tcl_Obj *pathPtr;	        /* Contains path to directory to search. */
    CONST char *pattern;	/* Pattern to match against. */
    Tcl_GlobTypeData *types;	/* Object containing list of acceptable types.
				 * May be NULL. In particular the directory
				 * flag is very important. */
{
    CONST TCHAR *native;






    if (pattern == NULL || (*pattern == '\0')) {
	Tcl_Obj *norm = Tcl_FSGetNormalizedPath(NULL, pathPtr);
	if (norm != NULL) {
	    /* Match a single file directly */
	    int len;
	    DWORD attr;







>
>
>
>
>







738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
    Tcl_Obj *pathPtr;	        /* Contains path to directory to search. */
    CONST char *pattern;	/* Pattern to match against. */
    Tcl_GlobTypeData *types;	/* Object containing list of acceptable types.
				 * May be NULL. In particular the directory
				 * flag is very important. */
{
    CONST TCHAR *native;

    if (types != NULL && types->type == TCL_GLOB_TYPE_MOUNT) {
	/* The native filesystem never adds mounts */
	return TCL_OK;
    }

    if (pattern == NULL || (*pattern == '\0')) {
	Tcl_Obj *norm = Tcl_FSGetNormalizedPath(NULL, pathPtr);
	if (norm != NULL) {
	    /* Match a single file directly */
	    int len;
	    DWORD attr;
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
			TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken)) {
	    /* 
	     * Unable to get current thread's token. 
	     */
	    goto accessError;
	}
	(*tclWinProcs->revertToSelfProc)();

	memset (&genMap, 0x00, sizeof (GENERIC_MAPPING));

	/* 
	 * Fill GenericMask type according to access priveleges
	 * we are checking.
	 */
	genMap.GenericAll = 0;
	if (mode & R_OK) {
	    genMap.GenericRead = FILE_GENERIC_READ;
	}
	if (mode & W_OK) {
	    genMap.GenericWrite = FILE_GENERIC_WRITE;
	}
	if (mode & X_OK) {
	    genMap.GenericExecute = FILE_GENERIC_EXECUTE;
	}
	(*tclWinProcs->mapGenericMaskProc)(&desiredAccess, &genMap);
	/* 
	 * Perform access check using the token. 
	 */
	if (!(*tclWinProcs->accessCheckProc )(sdPtr, hToken, desiredAccess, 
		&genMap, &privSet, &privSetSize, &grantedAccess,
		&accessYesNo)) {
	    /* 







>

>

|
|



|


|


|

|







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
			TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken)) {
	    /* 
	     * Unable to get current thread's token. 
	     */
	    goto accessError;
	}
	(*tclWinProcs->revertToSelfProc)();
	
	memset (&genMap, 0x00, sizeof (GENERIC_MAPPING));
	
	/* 
	 * Setup desiredAccess according to the access priveleges we
	 * are checking.
	 */
	genMap.GenericAll = 0;
	if (mode & R_OK) {
	    desiredAccess |= FILE_GENERIC_READ;
	}
	if (mode & W_OK) {
	    desiredAccess |= FILE_GENERIC_WRITE;
	}
	if (mode & X_OK) {
	    desiredAccess |= FILE_GENERIC_EXECUTE;
	}

	/* 
	 * Perform access check using the token. 
	 */
	if (!(*tclWinProcs->accessCheckProc )(sdPtr, hToken, desiredAccess, 
		&genMap, &privSet, &privSetSize, &grantedAccess,
		&accessYesNo)) {
	    /* 
1620
1621
1622
1623
1624
1625
1626


1627
1628
1629
1630
1631
1632
1633

/*
 *----------------------------------------------------------------------
 *
 * TclpGetCwd --
 *
 *	This function replaces the library version of getcwd().


 *
 * Results:
 *	The result is a pointer to a string specifying the current
 *	directory, or NULL if the current directory could not be
 *	determined.  If NULL is returned, an error message is left in the
 *	interp's result.  Storage for the result string is allocated in
 *	bufferPtr; the caller must call Tcl_DStringFree() when the result







>
>







1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642

/*
 *----------------------------------------------------------------------
 *
 * TclpGetCwd --
 *
 *	This function replaces the library version of getcwd().
 *      (Obsolete function, only retained for old extensions which
 *      may call it directly).
 *
 * Results:
 *	The result is a pointer to a string specifying the current
 *	directory, or NULL if the current directory could not be
 *	determined.  If NULL is returned, an error message is left in the
 *	interp's result.  Storage for the result string is allocated in
 *	bufferPtr; the caller must call Tcl_DStringFree() when the result
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
	Tcl_DStringAppend(bufferPtr, realFileName, -1);
	return 1;
    }
    return 0;
}
#endif




Tcl_Obj* 

















TclpObjGetCwd(interp)
    Tcl_Interp *interp;


{

    Tcl_DString ds;


    if (TclpGetCwd(interp, &ds) != NULL) {

	Tcl_Obj *cwdPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
	Tcl_IncrRefCount(cwdPtr);
	Tcl_DStringFree(&ds);





	return cwdPtr;

    } else {



	return NULL;
    }




}

int 
TclpObjAccess(pathPtr, mode)
    Tcl_Obj *pathPtr;
    int mode;
{







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

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







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
	Tcl_DStringAppend(bufferPtr, realFileName, -1);
	return 1;
    }
    return 0;
}
#endif

/*
 *---------------------------------------------------------------------------
 *
 * TclpGetNativeCwd --
 *
 *	This function replaces the library version of getcwd().
 *
 * Results:
 *	The input and output are filesystem paths in native form.  The
 *	result is either the given clientData, if the working directory
 *	hasn't changed, or a new clientData (owned by our caller),
 *	giving the new native path, or NULL if the current directory
 *	could not be determined.  If NULL is returned, the caller can
 *	examine the standard posix error codes to determine the cause of
 *	the problem.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

ClientData
TclpGetNativeCwd(clientData)
    ClientData clientData;
{
    WCHAR buffer[MAX_PATH];
    
    if ((*tclWinProcs->getCurrentDirectoryProc)(MAX_PATH, buffer) == 0) {
	TclWinConvertError(GetLastError());
	return NULL;
    }



    if (clientData != NULL) {
        if (tclWinProcs->useWide) {
	    /* unicode representation when running on NT/2K/XP */
	    if (wcscmp((CONST WCHAR*)clientData, 
		       (CONST WCHAR*)buffer) == 0) {
		return clientData;
	    }
	} else {
	    /* ansi representation when running on 95/98/ME */
	    if (strcmp((CONST char*)clientData, 
		       (CONST char*)buffer) == 0) {
		return clientData;
	    }
	}
    }
    
    return TclNativeDupInternalRep((ClientData)buffer);
}

int 
TclpObjAccess(pathPtr, mode)
    Tcl_Obj *pathPtr;
    int mode;
{
2133
2134
2135
2136
2137
2138
2139

2140



2141
2142
2143
2144
2145
2146
2147
TclpObjLink(pathPtr, toPtr, linkAction)
    Tcl_Obj *pathPtr;
    Tcl_Obj *toPtr;
    int linkAction;
{
    if (toPtr != NULL) {
	int res;

	TCHAR* LinkTarget = (TCHAR*)Tcl_FSGetNativePath(toPtr);



	TCHAR* LinkSource = (TCHAR*)Tcl_FSGetNativePath(pathPtr);
	if (LinkSource == NULL || LinkTarget == NULL) {
	    return NULL;
	}
	res = WinLink(LinkSource, LinkTarget, linkAction);
	if (res == 0) {
	    return toPtr;







>

>
>
>







2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
TclpObjLink(pathPtr, toPtr, linkAction)
    Tcl_Obj *pathPtr;
    Tcl_Obj *toPtr;
    int linkAction;
{
    if (toPtr != NULL) {
	int res;
#if 0
	TCHAR* LinkTarget = (TCHAR*)Tcl_FSGetNativePath(toPtr);
#else
	TCHAR* LinkTarget = (TCHAR*)Tcl_FSGetNativePath(Tcl_FSGetNormalizedPath(NULL,toPtr));
#endif
	TCHAR* LinkSource = (TCHAR*)Tcl_FSGetNativePath(pathPtr);
	if (LinkSource == NULL || LinkTarget == NULL) {
	    return NULL;
	}
	res = WinLink(LinkSource, LinkTarget, linkAction);
	if (res == 0) {
	    return toPtr;
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
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj*
TclpFilesystemPathType(pathObjPtr)
    Tcl_Obj* pathObjPtr;
{
#define VOL_BUF_SIZE 32
    int found;
    char volType[VOL_BUF_SIZE];
    char* firstSeparator;
    CONST char *path;
    
    Tcl_Obj *normPath = Tcl_FSGetNormalizedPath(NULL, pathObjPtr);
    if (normPath == NULL) return NULL;
    path = Tcl_GetString(normPath);
    if (path == NULL) return NULL;
    
    firstSeparator = strchr(path, '/');
    if (firstSeparator == NULL) {
	found = tclWinProcs->getVolumeInformationProc(
		Tcl_FSGetNativePath(pathObjPtr), NULL, 0, NULL, NULL, 
		NULL, (WCHAR *)volType, VOL_BUF_SIZE);
    } else {
	Tcl_Obj *driveName = Tcl_NewStringObj(path, firstSeparator - path+1);
	Tcl_IncrRefCount(driveName);
	found = tclWinProcs->getVolumeInformationProc(
		Tcl_FSGetNativePath(driveName), NULL, 0, NULL, NULL, 
		NULL, (WCHAR *)volType, VOL_BUF_SIZE);







|
|







|







|







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
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
Tcl_Obj*
TclpFilesystemPathType(pathPtr)
    Tcl_Obj* pathPtr;
{
#define VOL_BUF_SIZE 32
    int found;
    char volType[VOL_BUF_SIZE];
    char* firstSeparator;
    CONST char *path;
    
    Tcl_Obj *normPath = Tcl_FSGetNormalizedPath(NULL, pathPtr);
    if (normPath == NULL) return NULL;
    path = Tcl_GetString(normPath);
    if (path == NULL) return NULL;
    
    firstSeparator = strchr(path, '/');
    if (firstSeparator == NULL) {
	found = tclWinProcs->getVolumeInformationProc(
		Tcl_FSGetNativePath(pathPtr), NULL, 0, NULL, NULL, 
		NULL, (WCHAR *)volType, VOL_BUF_SIZE);
    } else {
	Tcl_Obj *driveName = Tcl_NewStringObj(path, firstSeparator - path+1);
	Tcl_IncrRefCount(driveName);
	found = tclWinProcs->getVolumeInformationProc(
		Tcl_FSGetNativePath(driveName), NULL, 0, NULL, NULL, 
		NULL, (WCHAR *)volType, VOL_BUF_SIZE);
2215
2216
2217
2218
2219
2220
2221








2222





2223
2224
2225
2226
2227
2228
2229
	Tcl_WinTCharToUtf(volType, -1, &ds);
	objPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds),Tcl_DStringLength(&ds));
	Tcl_DStringFree(&ds);
	return objPtr;
    }
#undef VOL_BUF_SIZE
}















/*
 *---------------------------------------------------------------------------
 *
 * TclpObjNormalizePath --
 *
 *	This function scans through a path specification and replaces it,







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







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
	Tcl_WinTCharToUtf(volType, -1, &ds);
	objPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds),Tcl_DStringLength(&ds));
	Tcl_DStringFree(&ds);
	return objPtr;
    }
#undef VOL_BUF_SIZE
}
/* 
 * This define can be turned on to experiment with a different way of
 * normalizing paths (using a different Windows API).  Unfortunately the
 * new path seems to take almost exactly the same amount of time as the
 * old path!  The primary time taken by normalization is in
 * GetFileAttributesEx/FindFirstFile or
 * GetFileAttributesEx/GetLongPathName.  Conversion to/from native is
 * not a significant factor at all.
 * 
 * Also, since we have to check for symbolic links (reparse points)
 * then we have to call GetFileAttributes on each path segment anyway,
 * so there's no benefit to doing anything clever there.
 */
/* #define TclNORM_LONG_PATH */

/*
 *---------------------------------------------------------------------------
 *
 * TclpObjNormalizePath --
 *
 *	This function scans through a path specification and replaces it,
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
 *
 * Side effects:
 *	The pathPtr string, which must contain a valid path, is
 *	possibly modified in place.
 *
 *---------------------------------------------------------------------------
 */

int
TclpObjNormalizePath(interp, pathPtr, nextCheckpoint)
    Tcl_Interp *interp;
    Tcl_Obj *pathPtr;
    int nextCheckpoint;
{
    char *lastValidPathEnd = NULL;







<







2300
2301
2302
2303
2304
2305
2306

2307
2308
2309
2310
2311
2312
2313
 *
 * Side effects:
 *	The pathPtr string, which must contain a valid path, is
 *	possibly modified in place.
 *
 *---------------------------------------------------------------------------
 */

int
TclpObjNormalizePath(interp, pathPtr, nextCheckpoint)
    Tcl_Interp *interp;
    Tcl_Obj *pathPtr;
    int nextCheckpoint;
{
    char *lastValidPathEnd = NULL;
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
	    currentPathEndPosition++;
	}
    } else {
	/* We're on WinNT or 2000 or XP */
	Tcl_Obj *temp = NULL;
	int isDrive = 1;
	Tcl_DString ds;

	currentPathEndPosition = path + nextCheckpoint;
	if (*currentPathEndPosition == '/') {
	    currentPathEndPosition++;
	}
	while (1) {
	    char cur = *currentPathEndPosition;
	    if ((cur == '/' || cur == 0) && (path != currentPathEndPosition)) {







|







2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
	    currentPathEndPosition++;
	}
    } else {
	/* We're on WinNT or 2000 or XP */
	Tcl_Obj *temp = NULL;
	int isDrive = 1;
	Tcl_DString ds;
	
	currentPathEndPosition = path + nextCheckpoint;
	if (*currentPathEndPosition == '/') {
	    currentPathEndPosition++;
	}
	while (1) {
	    char cur = *currentPathEndPosition;
	    if ((cur == '/' || cur == 0) && (path != currentPathEndPosition)) {
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
		 * Check for symlinks, except at last component
		 * of path (we don't follow final symlinks). Also
		 * a drive (C:/) for example, may sometimes have
		 * the reparse flag set for some reason I don't
		 * understand.  We therefore don't perform this
		 * check for drives.
		 */
		if (cur != 0 && !isDrive && (data.dwFileAttributes 
				 & FILE_ATTRIBUTE_REPARSE_POINT)) {
		    Tcl_Obj *to = WinReadLinkDirectory(nativePath);
		    if (to != NULL) {

			/* Read the reparse point ok */



			/* Tcl_GetStringFromObj(to, &pathLen); */





			nextCheckpoint = 0; /* pathLen */
			Tcl_AppendToObj(to, currentPathEndPosition, -1);
			/* Convert link to forward slashes */
			for (path = Tcl_GetString(to); *path != 0; path++) {
			    if (*path == '\\') *path = '/';
			}
			path = Tcl_GetString(to);
			currentPathEndPosition = path + nextCheckpoint;
			if (temp != NULL) {
			    Tcl_DecrRefCount(temp);
			}
			temp = to;
			/* Reset variables so we can restart normalization */
			isDrive = 1;
			Tcl_DStringFree(&dsNorm);
			Tcl_DStringInit(&dsNorm);
			Tcl_DStringFree(&ds);
			continue;
		    }
		}

		/*
		 * Now we convert the tail of the current path to its
		 * 'long form', and append it to 'dsNorm' which holds
		 * the current normalized path
		 */
		if (isDrive) {
		    WCHAR drive = ((WCHAR*)nativePath)[0];







|
|


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



















>







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
		 * Check for symlinks, except at last component
		 * of path (we don't follow final symlinks). Also
		 * a drive (C:/) for example, may sometimes have
		 * the reparse flag set for some reason I don't
		 * understand.  We therefore don't perform this
		 * check for drives.
		 */
		if (cur != 0 && !isDrive 
		  && (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
		    Tcl_Obj *to = WinReadLinkDirectory(nativePath);
		    if (to != NULL) {
			/* 
			 * Read the reparse point ok.  Now, reparse
			 * points need not be normalized, otherwise
			 * we could use: 
			 * 
			 * Tcl_GetStringFromObj(to, &pathLen); 
			 * nextCheckpoint = pathLen
			 * 
			 * So, instead we have to start from the
			 * beginning.
			 */
			nextCheckpoint = 0;
			Tcl_AppendToObj(to, currentPathEndPosition, -1);
			/* Convert link to forward slashes */
			for (path = Tcl_GetString(to); *path != 0; path++) {
			    if (*path == '\\') *path = '/';
			}
			path = Tcl_GetString(to);
			currentPathEndPosition = path + nextCheckpoint;
			if (temp != NULL) {
			    Tcl_DecrRefCount(temp);
			}
			temp = to;
			/* Reset variables so we can restart normalization */
			isDrive = 1;
			Tcl_DStringFree(&dsNorm);
			Tcl_DStringInit(&dsNorm);
			Tcl_DStringFree(&ds);
			continue;
		    }
		}
#ifndef TclNORM_LONG_PATH
		/*
		 * Now we convert the tail of the current path to its
		 * 'long form', and append it to 'dsNorm' which holds
		 * the current normalized path
		 */
		if (isDrive) {
		    WCHAR drive = ((WCHAR*)nativePath)[0];
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
			FindClose(handle);
			Tcl_DStringAppend(&dsNorm,(CONST char*)L"/", 
					  sizeof(WCHAR));
			Tcl_DStringAppend(&dsNorm,(TCHAR*)nativeName, 
					  (int) (wcslen(nativeName)*sizeof(WCHAR)));
		    }
		}

		Tcl_DStringFree(&ds);
		lastValidPathEnd = currentPathEndPosition;
		if (cur == 0) {
		    break;
		}
		/* 
		 * If we get here, we've got past one directory
		 * delimiter, so we know it is no longer a drive 
		 */
		isDrive = 0;
	    }
	    currentPathEndPosition++;
	}




















    }
    /* Common code path for all Windows platforms */
    nextCheckpoint = currentPathEndPosition - path;
    if (lastValidPathEnd != NULL) {
	/* 
	 * Concatenate the normalized string in dsNorm with the
	 * tail of the path which we didn't recognise.  The







>













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







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
			FindClose(handle);
			Tcl_DStringAppend(&dsNorm,(CONST char*)L"/", 
					  sizeof(WCHAR));
			Tcl_DStringAppend(&dsNorm,(TCHAR*)nativeName, 
					  (int) (wcslen(nativeName)*sizeof(WCHAR)));
		    }
		}
#endif
		Tcl_DStringFree(&ds);
		lastValidPathEnd = currentPathEndPosition;
		if (cur == 0) {
		    break;
		}
		/* 
		 * If we get here, we've got past one directory
		 * delimiter, so we know it is no longer a drive 
		 */
		isDrive = 0;
	    }
	    currentPathEndPosition++;
	}
#ifdef TclNORM_LONG_PATH
	/* 
	 * Convert the entire known path to long form.
	 */
	if (1) {
	    WCHAR wpath[MAX_PATH];
	    DWORD wpathlen;
	    CONST char *nativePath = Tcl_WinUtfToTChar(path, 
					lastValidPathEnd - path, &ds);
	    wpathlen = (*tclWinProcs->getLongPathNameProc)(nativePath, 
							   (TCHAR*)wpath, 
							   MAX_PATH);
	    /* We have to make the drive letter uppercase */
	    if (wpath[0] >= L'a') {
		wpath[0] -= (L'a' - L'A');
	    }
	    Tcl_DStringAppend(&dsNorm, (TCHAR*)wpath, wpathlen*sizeof(WCHAR));
	    Tcl_DStringFree(&ds);
	}
#endif
    }
    /* Common code path for all Windows platforms */
    nextCheckpoint = currentPathEndPosition - path;
    if (lastValidPathEnd != NULL) {
	/* 
	 * Concatenate the normalized string in dsNorm with the
	 * tail of the path which we didn't recognise.  The
2499
2500
2501
2502
2503
2504
2505

2506
2507
2508
2509
2510







2511
2512
2513
2514
2515
2516
2517
 */
int
TclpUtime(pathPtr, tval)
    Tcl_Obj *pathPtr;      /* File to modify */
    struct utimbuf *tval;  /* New modification date structure */
{
    int res;

    /* 
     * Windows uses a slightly different structure name and, possibly,
     * contents, so we have to copy the information over
     */
    struct _utimbuf buf;







    
    buf.actime = tval->actime;
    buf.modtime = tval->modtime;
    
    res = (*tclWinProcs->utimeProc)(Tcl_FSGetNativePath(pathPtr),&buf);
    return res;
}







>





>
>
>
>
>
>
>
|






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
 */
int
TclpUtime(pathPtr, tval)
    Tcl_Obj *pathPtr;      /* File to modify */
    struct utimbuf *tval;  /* New modification date structure */
{
    int res;
#ifndef __BORLANDC__
    /* 
     * Windows uses a slightly different structure name and, possibly,
     * contents, so we have to copy the information over
     */
    struct _utimbuf buf;
#else
    /*
     * Borland's compiler does not, but we still copy the content into a
     * local variable using the 'generic' name
     */
    struct utimbuf buf;
#endif

    buf.actime = tval->actime;
    buf.modtime = tval->modtime;
    
    res = (*tclWinProcs->utimeProc)(Tcl_FSGetNativePath(pathPtr),&buf);
    return res;
}
Changes to win/tclWinInit.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17







18
19
20
21
22
23
24
/* 
 * tclWinInit.c --
 *
 *	Contains the Windows-specific interpreter initialization functions.
 *
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 * All rights reserved.
 *
 * RCS: @(#) $Id: tclWinInit.c,v 1.41.2.1 2003/08/07 21:36:05 dgp Exp $
 */

#include "tclWinInt.h"
#include <winnt.h>
#include <winbase.h>
#include <lmcons.h>








/*
 * The following declaration is a workaround for some Microsoft brain damage.
 * The SYSTEM_INFO structure is different in various releases, even though the
 * layout is the same.  So we overlay our own structure on top of it so we
 * can access the interesting slots in a uniform way.
 */










|







>
>
>
>
>
>
>







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
/* 
 * tclWinInit.c --
 *
 *	Contains the Windows-specific interpreter initialization functions.
 *
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 * Copyright (c) 1998-1999 by Scriptics Corporation.
 * All rights reserved.
 *
 * RCS: @(#) $Id: tclWinInit.c,v 1.41.2.2 2004/02/07 05:48:12 dgp Exp $
 */

#include "tclWinInt.h"
#include <winnt.h>
#include <winbase.h>
#include <lmcons.h>

/*
 * GetUserName() is found in advapi32.dll
 */
#ifdef _MSC_VER
#   pragma comment(lib, "advapi32.lib")
#endif

/*
 * The following declaration is a workaround for some Microsoft brain damage.
 * The SYSTEM_INFO structure is different in various releases, even though the
 * layout is the same.  So we overlay our own structure on top of it so we
 * can access the interesting slots in a uniform way.
 */

193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
     * Initialize the substrings used when locating an executable.  The
     * installLib variable computes the path as though the executable
     * is installed.  The developLib computes the path as though the
     * executable is run from a develpment directory.
     */

    sprintf(installLib, "lib/tcl%s", TCL_VERSION);
    sprintf(developLib, "../tcl%s/library", TCL_PATCH_LEVEL);

    /*
     * Look for the library relative to default encoding dir.
     */

    str = Tcl_GetDefaultEncodingDir();
    if ((str != NULL) && (str[0] != '\0')) {







|







200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
     * Initialize the substrings used when locating an executable.  The
     * installLib variable computes the path as though the executable
     * is installed.  The developLib computes the path as though the
     * executable is run from a develpment directory.
     */

    sprintf(installLib, "lib/tcl%s", TCL_VERSION);
    sprintf(developLib, "tcl%s/library", TCL_PATCH_LEVEL);

    /*
     * Look for the library relative to default encoding dir.
     */

    str = Tcl_GetDefaultEncodingDir();
    if ((str != NULL) && (str[0] != '\0')) {
248
249
250
251
252
253
254



255















256
257
258
259
260
261
262
     
    /*
     * The variable path holds an absolute path.  Take care not to
     * overwrite pathv[0] since that might produce a relative path.
     */

    if (path != NULL) {



	Tcl_SplitPath(path, &pathc, &pathv);















	if (pathc > 2) {
	    str = pathv[pathc - 2];
	    pathv[pathc - 2] = installLib;
	    path = Tcl_JoinPath(pathc - 1, pathv, &ds);
	    pathv[pathc - 2] = str;
	    objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
	    Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);







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







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
     
    /*
     * The variable path holds an absolute path.  Take care not to
     * overwrite pathv[0] since that might produce a relative path.
     */

    if (path != NULL) {
	int i, origc;
	CONST char **origv;

	Tcl_SplitPath(path, &origc, &origv);
	pathc = 0;
	pathv = (CONST char **) ckalloc((unsigned int)(origc * sizeof(char *)));
	for (i=0; i< origc; i++) {
	    if (origv[i][0] == '.') {
		if (strcmp(origv[i], ".") == 0) {
		    /* do nothing */
		} else if (strcmp(origv[i], "..") == 0) {
		    pathc--;
		} else {
		    pathv[pathc++] = origv[i];
		}
	    } else {
		pathv[pathc++] = origv[i];
	    }
	}
	if (pathc > 2) {
	    str = pathv[pathc - 2];
	    pathv[pathc - 2] = installLib;
	    path = Tcl_JoinPath(pathc - 1, pathv, &ds);
	    pathv[pathc - 2] = str;
	    objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
	    Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
303
304
305
306
307
308
309

310
311
312
313
314
315
316
	    pathv[pathc - 4] = developLib;
	    path = Tcl_JoinPath(pathc - 3, pathv, &ds);
	    pathv[pathc - 4] = str;
	    objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
	    Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
	    Tcl_DStringFree(&ds);
	}

	ckfree((char *) pathv);
    }

    TclSetLibraryPath(pathPtr);
}

/*







>







328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
	    pathv[pathc - 4] = developLib;
	    path = Tcl_JoinPath(pathc - 3, pathv, &ds);
	    pathv[pathc - 4] = str;
	    objPtr = Tcl_NewStringObj(path, Tcl_DStringLength(&ds));
	    Tcl_ListObjAppendElement(NULL, pathPtr, objPtr);
	    Tcl_DStringFree(&ds);
	}
	ckfree((char *) origv);
	ckfree((char *) pathv);
    }

    TclSetLibraryPath(pathPtr);
}

/*
Changes to win/tclWinInt.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
 * tclWinInt.h --
 *
 *	Declarations of Windows-specific shared variables and procedures.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclWinInt.h,v 1.22.2.1 2003/10/16 02:28:04 dgp Exp $
 */

#ifndef _TCLWININT
#define _TCLWININT

#ifndef _TCLINT
#include "tclInt.h"










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/*
 * tclWinInt.h --
 *
 *	Declarations of Windows-specific shared variables and procedures.
 *
 * 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.
 *
 * RCS: @(#) $Id: tclWinInt.h,v 1.22.2.2 2004/02/07 05:48:12 dgp Exp $
 */

#ifndef _TCLWININT
#define _TCLWININT

#ifndef _TCLINT
#include "tclInt.h"
107
108
109
110
111
112
113

114
115
116
117
118
119
120
    
    INT (__cdecl *utimeProc)(CONST TCHAR*, struct _utimbuf *);
    /* 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);

    /* 
     * 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 lpFileName,
		     SECURITY_INFORMATION RequestedInformation,







>







107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
    
    INT (__cdecl *utimeProc)(CONST TCHAR*, struct _utimbuf *);
    /* 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 lpFileName,
		     SECURITY_INFORMATION RequestedInformation,
Changes to win/tclWinNotify.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclWinNotify.c --
 *
 *	This file contains Windows-specific procedures for the notifier,
 *	which is the lowest-level part of the Tcl event loop.  This file
 *	works together with ../generic/tclNotify.c.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWinNotify.c,v 1.12 2003/03/21 03:23:24 dgp Exp $
 */

#include "tclWinInt.h"

/*
 * The follwing static indicates whether this module has been initialized.
 */












|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* 
 * tclWinNotify.c --
 *
 *	This file contains Windows-specific procedures for the notifier,
 *	which is the lowest-level part of the Tcl event loop.  This file
 *	works together with ../generic/tclNotify.c.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWinNotify.c,v 1.12.2.1 2004/02/07 05:48:12 dgp Exp $
 */

#include "tclWinInt.h"

/*
 * The follwing static indicates whether this module has been initialized.
 */
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
	class.lpszMenuName = NULL;
	class.lpszClassName = "TclNotifier";
	class.lpfnWndProc = NotifierProc;
	class.hIcon = NULL;
	class.hCursor = NULL;

	if (!RegisterClassA(&class)) {
	    panic("Unable to register TclNotifier window class");
	}
    }
    notifierCount++;
    Tcl_MutexUnlock(&notifierMutex);

    tsdPtr->pending = 0;
    tsdPtr->timerActive = 0;







|







103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
	class.lpszMenuName = NULL;
	class.lpszClassName = "TclNotifier";
	class.lpfnWndProc = NotifierProc;
	class.hIcon = NULL;
	class.hCursor = NULL;

	if (!RegisterClassA(&class)) {
	    Tcl_Panic("Unable to register TclNotifier window class");
	}
    }
    notifierCount++;
    Tcl_MutexUnlock(&notifierMutex);

    tsdPtr->pending = 0;
    tsdPtr->timerActive = 0;
Changes to win/tclWinPipe.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclWinPipe.c --
 *
 *	This file implements the Windows-specific exec pipeline functions,
 *	the "pipe" channel driver, and the "pid" Tcl command.
 *
 * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWinPipe.c,v 1.35.2.2 2003/10/16 02:28:04 dgp Exp $
 */

#include "tclWinInt.h"

#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclWinPipe.c --
 *
 *	This file implements the Windows-specific exec pipeline functions,
 *	the "pipe" channel driver, and the "pid" Tcl command.
 *
 * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWinPipe.c,v 1.35.2.3 2004/02/07 05:48:12 dgp Exp $
 */

#include "tclWinInt.h"

#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
		    ckfree((char *) filePtr);
		    return -1;
		}
	    }
	    break;

	default:
	    panic("TclpCloseFile: unexpected file type");
    }

    ckfree((char *) filePtr);
    return 0;
}

/*







|







870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
		    ckfree((char *) filePtr);
		    return -1;
		}
	    }
	    break;

	default:
	    Tcl_Panic("TclpCloseFile: unexpected file type");
    }

    ckfree((char *) filePtr);
    return 0;
}

/*
901
902
903
904
905
906
907


908
909
910
911
912
913
914
 */

unsigned long
TclpGetPid(
    Tcl_Pid pid)		/* The HANDLE of the child process. */
{
    ProcInfo *infoPtr;



    Tcl_MutexLock(&pipeMutex);
    for (infoPtr = procList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) {
	if (infoPtr->hProcess == (HANDLE) pid) {
	    Tcl_MutexUnlock(&pipeMutex);
	    return infoPtr->dwProcessId;
	}







>
>







901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
 */

unsigned long
TclpGetPid(
    Tcl_Pid pid)		/* The HANDLE of the child process. */
{
    ProcInfo *infoPtr;

    PipeInit();

    Tcl_MutexLock(&pipeMutex);
    for (infoPtr = procList; infoPtr != NULL; infoPtr = infoPtr->nextPtr) {
	if (infoPtr->hProcess == (HANDLE) pid) {
	    Tcl_MutexUnlock(&pipeMutex);
	    return infoPtr->dwProcessId;
	}
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
		Tcl_DStringAppend(&pipeDll, TCL_PIPE_DLL, -1);
		tclExePtr = Tcl_NewStringObj(TclpFindExecutable(""), -1);
		start = Tcl_GetStringFromObj(tclExePtr, &i);
		for (end = start + (i-1); end > start; end--) {
		    if (*end == '/')
		        break;
		}
		if (*end != '/')
		    panic("no / in executable path name");

		i = (end - start) + 1;
		pipeDllPtr = Tcl_NewStringObj(start, i);
		Tcl_AppendToObj(pipeDllPtr, Tcl_DStringValue(&pipeDll), -1);
		Tcl_IncrRefCount(pipeDllPtr);
		if (Tcl_FSConvertToPathType(interp, pipeDllPtr) != TCL_OK)
		    panic("Tcl_FSConvertToPathType failed");

		fileExists = (Tcl_FSAccess(pipeDllPtr, F_OK) == 0);
		if (!fileExists) {
		    panic("Tcl pipe dll \"%s\" not found",
		        Tcl_DStringValue(&pipeDll));
		}
		Tcl_DStringAppend(&cmdLine, Tcl_DStringValue(&pipeDll), -1);
		Tcl_DecrRefCount(tclExePtr);
		Tcl_DecrRefCount(pipeDllPtr);
		Tcl_DStringFree(&pipeDll);
	    }







|
|
>




|
|
>


|







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
		Tcl_DStringAppend(&pipeDll, TCL_PIPE_DLL, -1);
		tclExePtr = Tcl_NewStringObj(TclpFindExecutable(""), -1);
		start = Tcl_GetStringFromObj(tclExePtr, &i);
		for (end = start + (i-1); end > start; end--) {
		    if (*end == '/')
		        break;
		}
		if (*end != '/') {
		    Tcl_Panic("no / in executable path name");
		}
		i = (end - start) + 1;
		pipeDllPtr = Tcl_NewStringObj(start, i);
		Tcl_AppendToObj(pipeDllPtr, Tcl_DStringValue(&pipeDll), -1);
		Tcl_IncrRefCount(pipeDllPtr);
		if (Tcl_FSConvertToPathType(interp, pipeDllPtr) != TCL_OK) {
		    Tcl_Panic("Tcl_FSConvertToPathType failed");
		}
		fileExists = (Tcl_FSAccess(pipeDllPtr, F_OK) == 0);
		if (!fileExists) {
		    Tcl_Panic("Tcl pipe dll \"%s\" not found",
		        Tcl_DStringValue(&pipeDll));
		}
		Tcl_DStringAppend(&cmdLine, Tcl_DStringValue(&pipeDll), -1);
		Tcl_DecrRefCount(tclExePtr);
		Tcl_DecrRefCount(pipeDllPtr);
		Tcl_DStringFree(&pipeDll);
	    }
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
    Tcl_DStringAppend(&ds, Tcl_DStringValue(linePtr), -1);
    
    for (i = 0; i < argc; i++) {
	if (i == 0) {
	    arg = executable;
	} else {
	    arg = argv[i];

	}

	if(Tcl_DStringLength(&ds) > 0) Tcl_DStringAppend(&ds, " ", 1);

	quote = 0;
	if (arg[0] == '\0') {
	    quote = 1;
	} else {


	    for (start = arg; *start != '\0'; start++) {

		if (isspace(*start)) { /* INTL: ISO space. */
		    quote = 1;
		    break;
		}
	    }
	}
	if (quote) {
	    Tcl_DStringAppend(&ds, "\"", 1);
	}

	start = arg;	    
	for (special = arg; ; ) {
	    if ((*special == '\\') && 
		    (special[1] == '\\' || special[1] == '"')) {
		Tcl_DStringAppend(&ds, start, special - start);
		start = special;
		while (1) {
		    special++;
		    if (*special == '"') {
			/* 
			 * N backslashes followed a quote -> insert 
			 * N * 2 + 1 backslashes then a quote.
			 */

			Tcl_DStringAppend(&ds, start, special - start);

			break;
		    }
		    if (*special != '\\') {
			break;
		    }
		}
		Tcl_DStringAppend(&ds, start, special - start);
		start = special;
	    }
	    if (*special == '"') {
		Tcl_DStringAppend(&ds, start, special - start);
		Tcl_DStringAppend(&ds, "\\\"", 2);
		start = special + 1;
	    }
	    if (*special == '{') {
		Tcl_DStringAppend(&ds, start, special - start);
		Tcl_DStringAppend(&ds, "\\{", 2);
		start = special + 1;
	    }
	    if (*special == '\0') {
		break;
	    }
	    special++;
	}
	Tcl_DStringAppend(&ds, start, special - start);
	if (quote) {
	    Tcl_DStringAppend(&ds, "\"", 1);
	}
    }
    Tcl_DStringFree(linePtr);
    Tcl_WinUtfToTChar(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds), linePtr);
    Tcl_DStringFree(&ds);







>


<
<




>
>
|
>
|








<



|
|



|





|
>






|



|



<
<
<
<
<





|







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
    Tcl_DStringAppend(&ds, Tcl_DStringValue(linePtr), -1);
    
    for (i = 0; i < argc; i++) {
	if (i == 0) {
	    arg = executable;
	} else {
	    arg = argv[i];
	    Tcl_DStringAppend(&ds, " ", 1);
	}



	quote = 0;
	if (arg[0] == '\0') {
	    quote = 1;
	} else {
	    int count;
	    Tcl_UniChar ch;
	    for (start = arg; *start != '\0'; start += count) {
	        count = Tcl_UtfToUniChar(start, &ch);
		if (Tcl_UniCharIsSpace(ch)) { /* INTL: ISO space. */
		    quote = 1;
		    break;
		}
	    }
	}
	if (quote) {
	    Tcl_DStringAppend(&ds, "\"", 1);
	}

	start = arg;	    
	for (special = arg; ; ) {
	    if ((*special == '\\') && 
		    (special[1] == '\\' || special[1] == '"' || (quote && special[1] == '\0'))) {
		Tcl_DStringAppend(&ds, start, (int) (special - start));
		start = special;
		while (1) {
		    special++;
		    if (*special == '"' || (quote && *special == '\0')) {
			/* 
			 * N backslashes followed a quote -> insert 
			 * N * 2 + 1 backslashes then a quote.
			 */

			Tcl_DStringAppend(&ds, start,
				(int) (special - start));
			break;
		    }
		    if (*special != '\\') {
			break;
		    }
		}
		Tcl_DStringAppend(&ds, start, (int) (special - start));
		start = special;
	    }
	    if (*special == '"') {
		Tcl_DStringAppend(&ds, start, (int) (special - start));
		Tcl_DStringAppend(&ds, "\\\"", 2);
		start = special + 1;
	    }





	    if (*special == '\0') {
		break;
	    }
	    special++;
	}
	Tcl_DStringAppend(&ds, start, (int) (special - start));
	if (quote) {
	    Tcl_DStringAppend(&ds, "\"", 1);
	}
    }
    Tcl_DStringFree(linePtr);
    Tcl_WinUtfToTChar(Tcl_DStringValue(&ds), Tcl_DStringLength(&ds), linePtr);
    Tcl_DStringFree(&ds);
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

Tcl_Pid
Tcl_WaitPid(
    Tcl_Pid pid,
    int *statPtr,
    int options)
{
    ProcInfo *infoPtr, **prevPtrPtr;
    DWORD flags;
    Tcl_Pid result;
    DWORD ret, exitCode;

    PipeInit();

    /*
     * If no pid is specified, do nothing.
     */
    
    if (pid == 0) {
	*statPtr = 0;
	return 0;
    }

    /*
     * Find the process on the process list.
     */

    Tcl_MutexLock(&pipeMutex);
    prevPtrPtr = &procList;
    for (infoPtr = procList; infoPtr != NULL;
	    prevPtrPtr = &infoPtr->nextPtr, infoPtr = infoPtr->nextPtr) {
	 if (infoPtr->hProcess == (HANDLE) pid) {

	    break;
	}
    }
    Tcl_MutexUnlock(&pipeMutex);

    /*
     * If the pid is not one of the processes we know about (we started it)







|
















|







>







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

Tcl_Pid
Tcl_WaitPid(
    Tcl_Pid pid,
    int *statPtr,
    int options)
{
    ProcInfo *infoPtr = NULL, **prevPtrPtr;
    DWORD flags;
    Tcl_Pid result;
    DWORD ret, exitCode;

    PipeInit();

    /*
     * If no pid is specified, do nothing.
     */
    
    if (pid == 0) {
	*statPtr = 0;
	return 0;
    }

    /*
     * Find the process and cut it from the process list.
     */

    Tcl_MutexLock(&pipeMutex);
    prevPtrPtr = &procList;
    for (infoPtr = procList; infoPtr != NULL;
	    prevPtrPtr = &infoPtr->nextPtr, infoPtr = infoPtr->nextPtr) {
	 if (infoPtr->hProcess == (HANDLE) pid) {
	    *prevPtrPtr = infoPtr->nextPtr;
	    break;
	}
    }
    Tcl_MutexUnlock(&pipeMutex);

    /*
     * If the pid is not one of the processes we know about (we started it)
2530
2531
2532
2533
2534
2535
2536







2537
2538
2539
2540
2541
2542
2543
    } else {
	flags = INFINITE;
    }
    ret = WaitForSingleObject(infoPtr->hProcess, flags);
    if (ret == WAIT_TIMEOUT) {
	*statPtr = 0;
	if (options & WNOHANG) {







	    return 0;
	} else {
	    result = 0;
	}
    } else if (ret == WAIT_OBJECT_0) {
	GetExitCodeProcess(infoPtr->hProcess, &exitCode);
	if (exitCode & 0xC0000000) {







>
>
>
>
>
>
>







2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
    } else {
	flags = INFINITE;
    }
    ret = WaitForSingleObject(infoPtr->hProcess, flags);
    if (ret == WAIT_TIMEOUT) {
	*statPtr = 0;
	if (options & WNOHANG) {
	    /*
	     * Re-insert this infoPtr back on the list.
	     */
	    Tcl_MutexLock(&pipeMutex);
	    infoPtr->nextPtr = procList;
	    procList = infoPtr;
	    Tcl_MutexUnlock(&pipeMutex);
	    return 0;
	} else {
	    result = 0;
	}
    } else if (ret == WAIT_OBJECT_0) {
	GetExitCodeProcess(infoPtr->hProcess, &exitCode);
	if (exitCode & 0xC0000000) {
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
    } else {
	errno = ECHILD;
        *statPtr = ECHILD;
	result = (Tcl_Pid) -1;
    }

    /*
     * Remove the process from the process list and close the process handle.
     */

    CloseHandle(infoPtr->hProcess);
    *prevPtrPtr = infoPtr->nextPtr;
    ckfree((char*)infoPtr);

    return result;
}

/*
 *----------------------------------------------------------------------







|



<







2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611

2612
2613
2614
2615
2616
2617
2618
    } else {
	errno = ECHILD;
        *statPtr = ECHILD;
	result = (Tcl_Pid) -1;
    }

    /*
     * Officially close the process handle.
     */

    CloseHandle(infoPtr->hProcess);

    ckfree((char*)infoPtr);

    return result;
}

/*
 *----------------------------------------------------------------------
Changes to win/tclWinReg.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17



18
19
20
21
22
23
24
/*
 * tclWinReg.c --
 *
 *	This file contains the implementation of the "registry" Tcl
 *	built-in command.  This command is built as a dynamically
 *	loadable extension in a separate DLL.
 *
 * Copyright (c) 1997 by 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.
 *
 * RCS: @(#) $Id: tclWinReg.c,v 1.21.4.1 2003/08/07 21:36:05 dgp Exp $
 */

#include <tclPort.h>



#include <stdlib.h>

/*
 * TCL_STORAGE_CLASS is set unconditionally to DLLEXPORT because the
 * Registry_Init declaration is in the source file itself, which is only
 * accessed when we are building a library.
 */













|



>
>
>







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
/*
 * tclWinReg.c --
 *
 *	This file contains the implementation of the "registry" Tcl
 *	built-in command.  This command is built as a dynamically
 *	loadable extension in a separate DLL.
 *
 * Copyright (c) 1997 by 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.
 *
 * RCS: @(#) $Id: tclWinReg.c,v 1.21.4.2 2004/02/07 05:48:12 dgp Exp $
 */

#include <tclPort.h>
#ifdef _MSC_VER
#   pragma comment (lib, "advapi32.lib")
#endif
#include <stdlib.h>

/*
 * TCL_STORAGE_CLASS is set unconditionally to DLLEXPORT because the
 * Registry_Init declaration is in the source file itself, which is only
 * accessed when we are building a library.
 */
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
 *----------------------------------------------------------------------
 */

int
Registry_Init(
    Tcl_Interp *interp)
{
    if (!Tcl_InitStubs(interp, "8.0", 0)) {
	return TCL_ERROR;
    }

    /*
     * Determine if the unicode interfaces are available and select the
     * appropriate registry function table.
     */

    if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
	regWinProcs = &unicodeProcs;
    } else {
	regWinProcs = &asciiProcs;
    }

    Tcl_CreateObjCommand(interp, "registry", RegistryObjCmd, NULL, NULL);
    return Tcl_PkgProvide(interp, "registry", "1.1.2");
}

/*
 *----------------------------------------------------------------------
 *
 * RegistryObjCmd --
 *







|















|







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
 *----------------------------------------------------------------------
 */

int
Registry_Init(
    Tcl_Interp *interp)
{
    if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
	return TCL_ERROR;
    }

    /*
     * Determine if the unicode interfaces are available and select the
     * appropriate registry function table.
     */

    if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_NT) {
	regWinProcs = &unicodeProcs;
    } else {
	regWinProcs = &asciiProcs;
    }

    Tcl_CreateObjCommand(interp, "registry", RegistryObjCmd, NULL, NULL);
    return Tcl_PkgProvide(interp, "registry", "1.1.3");
}

/*
 *----------------------------------------------------------------------
 *
 * RegistryObjCmd --
 *
Changes to win/tclWinSock.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 
 * tclWinSock.c --
 *
 *	This file contains Windows-specific socket related code.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWinSock.c,v 1.37.2.1 2003/08/27 21:07:22 dgp Exp $
 */

#include "tclWinInt.h"

/*
 * Make sure to remove the redirection defines set in tclWinPort.h
 * that is in use in other sections of the core, except for us.










|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* 
 * tclWinSock.c --
 *
 *	This file contains Windows-specific socket related code.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWinSock.c,v 1.37.2.2 2004/02/07 05:48:12 dgp Exp $
 */

#include "tclWinInt.h"

/*
 * Make sure to remove the redirection defines set in tclWinPort.h
 * that is in use in other sections of the core, except for us.
622
623
624
625
626
627
628

629
630
631
632
633
634
635
636









637
638
639
640
641
642
643
	(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);

    if (tsdPtr != NULL && tsdPtr->socketThread != NULL) {
	DWORD exitCode;

	GetExitCodeThread(tsdPtr->socketThread, &exitCode);
	if (exitCode == STILL_ACTIVE) {

	    PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);

	    /*
	     * Wait for the thread to close.  This ensures that we are
	     * completely cleaned up before we leave this function. 
	     */

	    WaitForSingleObject(tsdPtr->socketThread, INFINITE);









	}
	CloseHandle(tsdPtr->socketThread);
	tsdPtr->socketThread = NULL;
	CloseHandle(tsdPtr->readyEvent);
	CloseHandle(tsdPtr->socketListLock);

	Tcl_DeleteThreadExitHandler(SocketThreadExitHandler, NULL);







>







|
>
>
>
>
>
>
>
>
>







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
	(ThreadSpecificData *)TclThreadDataKeyGet(&dataKey);

    if (tsdPtr != NULL && tsdPtr->socketThread != NULL) {
	DWORD exitCode;

	GetExitCodeThread(tsdPtr->socketThread, &exitCode);
	if (exitCode == STILL_ACTIVE) {
	    DWORD dwWait;
	    PostMessage(tsdPtr->hwnd, SOCKET_TERMINATE, 0, 0);

	    /*
	     * Wait for the thread to close.  This ensures that we are
	     * completely cleaned up before we leave this function. 
	     */

	    dwWait = WaitForSingleObject(tsdPtr->socketThread, 100);
	    if (dwWait == WAIT_TIMEOUT) {
		/*
		 * Avoids a lock-up, just in case it is needed from an
		 * unclean exit condition when the thread appears
		 * running, but isn't.
		 */

		TerminateThread(tsdPtr->socketThread, EXIT_FAILURE);
	    }
	}
	CloseHandle(tsdPtr->socketThread);
	tsdPtr->socketThread = NULL;
	CloseHandle(tsdPtr->readyEvent);
	CloseHandle(tsdPtr->socketListLock);

	Tcl_DeleteThreadExitHandler(SocketThreadExitHandler, NULL);
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
	 * have to watch out for the channel being deleted out from under
	 * us.  This may cause a redundant trip through the event loop, but
	 * it's simpler than trying to do unwind protection.
	 */

	Tcl_Time blockTime = { 0, 0 };
	Tcl_SetMaxBlockTime(&blockTime);
	mask |= TCL_READABLE;
    } else if (events & FD_READ) {
	fd_set readFds;
	struct timeval timeout;

	/*
	 * We must check to see if data is really available, since someone
	 * could have consumed the data in the meantime.  Turn off async







|







875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
	 * have to watch out for the channel being deleted out from under
	 * us.  This may cause a redundant trip through the event loop, but
	 * it's simpler than trying to do unwind protection.
	 */

	Tcl_Time blockTime = { 0, 0 };
	Tcl_SetMaxBlockTime(&blockTime);
	mask |= TCL_READABLE|TCL_WRITABLE;
    } else if (events & FD_READ) {
	fd_set readFds;
	struct timeval timeout;

	/*
	 * We must check to see if data is really available, since someone
	 * could have consumed the data in the meantime.  Turn off async
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266

    if (!infoPtr->acceptProc) {    
        infoPtr->watchEvents = 0;
	if (mask & TCL_READABLE) {
	    infoPtr->watchEvents |= (FD_READ|FD_CLOSE|FD_ACCEPT);
	}
	if (mask & TCL_WRITABLE) {
	    infoPtr->watchEvents |= (FD_WRITE|FD_CONNECT);
	}
      
	/*
	 * If there are any conditions already set, then tell the notifier to poll
	 * rather than block.
	 */








|







2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276

    if (!infoPtr->acceptProc) {    
        infoPtr->watchEvents = 0;
	if (mask & TCL_READABLE) {
	    infoPtr->watchEvents |= (FD_READ|FD_CLOSE|FD_ACCEPT);
	}
	if (mask & TCL_WRITABLE) {
	    infoPtr->watchEvents |= (FD_WRITE|FD_CLOSE|FD_CONNECT);
	}
      
	/*
	 * If there are any conditions already set, then tell the notifier to poll
	 * rather than block.
	 */

2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
    /*
     * This could happen if the channel was created in one thread
     * and then moved to another without updating the thread
     * local data in each thread.
     */

    if (!removed) {
        panic("file info ptr not on thread channel list");
    }

    /*
     * Stop notifications for the socket to occur in this thread.
     */

    SendMessage(tsdPtr->hwnd, SOCKET_SELECT,







|







2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
    /*
     * This could happen if the channel was created in one thread
     * and then moved to another without updating the thread
     * local data in each thread.
     */

    if (!removed) {
        Tcl_Panic("file info ptr not on thread channel list");
    }

    /*
     * Stop notifications for the socket to occur in this thread.
     */

    SendMessage(tsdPtr->hwnd, SOCKET_SELECT,
Changes to win/tclWinThrd.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclWinThread.c --
 *
 *	This file implements the Windows-specific thread operations.
 *
 * Copyright (c) 1998 by Sun Microsystems, Inc.
 * Copyright (c) 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.
 *
 * RCS: @(#) $Id: tclWinThrd.c,v 1.26 2003/05/13 10:16:17 mistachkin Exp $
 */

#include "tclWinInt.h"

#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclWinThread.c --
 *
 *	This file implements the Windows-specific thread operations.
 *
 * Copyright (c) 1998 by Sun Microsystems, Inc.
 * Copyright (c) 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.
 *
 * RCS: @(#) $Id: tclWinThrd.c,v 1.26.2.1 2004/02/07 05:48:12 dgp Exp $
 */

#include "tclWinInt.h"

#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
    MASTER_LOCK;
    if (*keyPtr == NULL) {
	indexPtr = (DWORD *)ckalloc(sizeof(DWORD));
	newKey = TlsAlloc();
        if (newKey != TLS_OUT_OF_INDEXES) {
            *indexPtr = newKey;
        } else {
            panic("TlsAlloc failed from TclpThreadDataKeyInit!"); /* this should be a fatal error */
        }
	*keyPtr = (Tcl_ThreadDataKey)indexPtr;
	TclRememberDataKey(keyPtr);
    }
    MASTER_UNLOCK;
}








|







544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
    MASTER_LOCK;
    if (*keyPtr == NULL) {
	indexPtr = (DWORD *)ckalloc(sizeof(DWORD));
	newKey = TlsAlloc();
        if (newKey != TLS_OUT_OF_INDEXES) {
            *indexPtr = newKey;
        } else {
            Tcl_Panic("TlsAlloc failed from TclpThreadDataKeyInit!"); /* this should be a fatal error */
        }
	*keyPtr = (Tcl_ThreadDataKey)indexPtr;
	TclRememberDataKey(keyPtr);
    }
    MASTER_UNLOCK;
}

581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
    DWORD *indexPtr = *(DWORD **)keyPtr;
    LPVOID result;
    if (indexPtr == NULL) {
	return NULL;
    } else {
        result = TlsGetValue(*indexPtr);
        if ((result == NULL) && (GetLastError() != NO_ERROR)) {
            panic("TlsGetValue failed from TclpThreadDataKeyGet!");
        }
	return result;
    }
}

/*
 *----------------------------------------------------------------------







|







581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
    DWORD *indexPtr = *(DWORD **)keyPtr;
    LPVOID result;
    if (indexPtr == NULL) {
	return NULL;
    } else {
        result = TlsGetValue(*indexPtr);
        if ((result == NULL) && (GetLastError() != NO_ERROR)) {
            Tcl_Panic("TlsGetValue failed from TclpThreadDataKeyGet!");
        }
	return result;
    }
}

/*
 *----------------------------------------------------------------------
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
				 * really (pthread_key_t **) */
    VOID *data;			/* Thread local storage */
{
    DWORD *indexPtr = *(DWORD **)keyPtr;
    BOOL success;
    success = TlsSetValue(*indexPtr, (void *)data);
    if (!success) {
        panic("TlsSetValue failed from TclpThreadDataKeySet!");
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TclpFinalizeThreadData --







|







614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
				 * really (pthread_key_t **) */
    VOID *data;			/* Thread local storage */
{
    DWORD *indexPtr = *(DWORD **)keyPtr;
    BOOL success;
    success = TlsSetValue(*indexPtr, (void *)data);
    if (!success) {
        Tcl_Panic("TlsSetValue failed from TclpThreadDataKeySet!");
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TclpFinalizeThreadData --
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
    if (*keyPtr != NULL) {
	indexPtr = *(DWORD **)keyPtr;
	result = (VOID *)TlsGetValue(*indexPtr);
	if (result != NULL) {
	    ckfree((char *)result);
	    success = TlsSetValue(*indexPtr, (void *)NULL);
            if (!success) {
                panic("TlsSetValue failed from TclpFinalizeThreadData!");
            }
	} else {
            if (GetLastError() != NO_ERROR) {
                panic("TlsGetValue failed from TclpFinalizeThreadData!");
            }
	}
    }
}

/*
 *----------------------------------------------------------------------







|



|







653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
    if (*keyPtr != NULL) {
	indexPtr = *(DWORD **)keyPtr;
	result = (VOID *)TlsGetValue(*indexPtr);
	if (result != NULL) {
	    ckfree((char *)result);
	    success = TlsSetValue(*indexPtr, (void *)NULL);
            if (!success) {
                Tcl_Panic("TlsSetValue failed from TclpFinalizeThreadData!");
            }
	} else {
            if (GetLastError() != NO_ERROR) {
                Tcl_Panic("TlsGetValue failed from TclpFinalizeThreadData!");
            }
	}
    }
}

/*
 *----------------------------------------------------------------------
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
{
    DWORD *indexPtr;
    BOOL success;
    if (*keyPtr != NULL) {
	indexPtr = *(DWORD **)keyPtr;
	success = TlsFree(*indexPtr);
        if (!success) {
            panic("TlsFree failed from TclpFinalizeThreadDataKey!");
        }
	ckfree((char *)indexPtr);
	*keyPtr = NULL;
    }
}

/*







|







693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
{
    DWORD *indexPtr;
    BOOL success;
    if (*keyPtr != NULL) {
	indexPtr = *(DWORD **)keyPtr;
	success = TlsFree(*indexPtr);
        if (!success) {
            Tcl_Panic("TlsFree failed from TclpFinalizeThreadDataKey!");
        }
	ckfree((char *)indexPtr);
	*keyPtr = NULL;
    }
}

/*
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916

void
Tcl_ConditionNotify(condPtr)
    Tcl_Condition *condPtr;
{
    WinCondition *winCondPtr;
    ThreadSpecificData *tsdPtr;
    if (condPtr != NULL) {
	winCondPtr = *((WinCondition **)condPtr);

	/*
	 * Loop through all the threads waiting on the condition
	 * and notify them (i.e., broadcast semantics).  The queue
	 * manipulation is guarded by the per-condition coordinating mutex.
	 */







|







902
903
904
905
906
907
908
909
910
911
912
913
914
915
916

void
Tcl_ConditionNotify(condPtr)
    Tcl_Condition *condPtr;
{
    WinCondition *winCondPtr;
    ThreadSpecificData *tsdPtr;
    if (*condPtr != NULL) {
	winCondPtr = *((WinCondition **)condPtr);

	/*
	 * Loop through all the threads waiting on the condition
	 * and notify them (i.e., broadcast semantics).  The queue
	 * manipulation is guarded by the per-condition coordinating mutex.
	 */
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
    struct lock {
        Tcl_Mutex        tlock;
        CRITICAL_SECTION wlock;
    } *lockPtr;

    lockPtr = malloc(sizeof(struct lock));
    if (lockPtr == NULL) {
	panic("could not allocate lock");
    }
    lockPtr->tlock = (Tcl_Mutex) &lockPtr->wlock;
    InitializeCriticalSection(&lockPtr->wlock);
    return &lockPtr->tlock;
}

void *







|







1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
    struct lock {
        Tcl_Mutex        tlock;
        CRITICAL_SECTION wlock;
    } *lockPtr;

    lockPtr = malloc(sizeof(struct lock));
    if (lockPtr == NULL) {
	Tcl_Panic("could not allocate lock");
    }
    lockPtr->tlock = (Tcl_Mutex) &lockPtr->wlock;
    InitializeCriticalSection(&lockPtr->wlock);
    return &lockPtr->tlock;
}

void *
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
	 * We need to make sure that TclWinFreeAllocCache is called
	 * on each thread that calls this, but only on threads that
	 * call this.
	 */
    	key = TlsAlloc();
	once = 1;
	if (key == TLS_OUT_OF_INDEXES) {
	    panic("could not allocate thread local storage");
	}
    }

    result = TlsGetValue(key);
    if ((result == NULL) && (GetLastError() != NO_ERROR)) {
        panic("TlsGetValue failed from TclpGetAllocCache!");
    }
    return result;
}

void
TclpSetAllocCache(void *ptr)
{
    BOOL success;
    success = TlsSetValue(key, ptr);
    if (!success) {
        panic("TlsSetValue failed from TclpSetAllocCache!");
    }
}

void
TclWinFreeAllocCache(void)
{
    void *ptr;
    BOOL success;

    ptr = TlsGetValue(key);
    if (ptr != NULL) {
	success = TlsSetValue(key, NULL);
        if (!success) {
            panic("TlsSetValue failed from TclWinFreeAllocCache!");
        }
	TclFreeAllocCache(ptr);
    } else {
      if (GetLastError() != NO_ERROR) {
          panic("TlsGetValue failed from TclWinFreeAllocCache!");
      }
    }
}

#endif /* USE_THREAD_ALLOC */
#endif /* TCL_THREADS */







|





|










|













|




|






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
	 * We need to make sure that TclWinFreeAllocCache is called
	 * on each thread that calls this, but only on threads that
	 * call this.
	 */
    	key = TlsAlloc();
	once = 1;
	if (key == TLS_OUT_OF_INDEXES) {
	    Tcl_Panic("could not allocate thread local storage");
	}
    }

    result = TlsGetValue(key);
    if ((result == NULL) && (GetLastError() != NO_ERROR)) {
        Tcl_Panic("TlsGetValue failed from TclpGetAllocCache!");
    }
    return result;
}

void
TclpSetAllocCache(void *ptr)
{
    BOOL success;
    success = TlsSetValue(key, ptr);
    if (!success) {
        Tcl_Panic("TlsSetValue failed from TclpSetAllocCache!");
    }
}

void
TclWinFreeAllocCache(void)
{
    void *ptr;
    BOOL success;

    ptr = TlsGetValue(key);
    if (ptr != NULL) {
	success = TlsSetValue(key, NULL);
        if (!success) {
            Tcl_Panic("TlsSetValue failed from TclWinFreeAllocCache!");
        }
	TclFreeAllocCache(ptr);
    } else {
      if (GetLastError() != NO_ERROR) {
          Tcl_Panic("TlsGetValue failed from TclWinFreeAllocCache!");
      }
    }
}

#endif /* USE_THREAD_ALLOC */
#endif /* TCL_THREADS */
Changes to win/tclWinTime.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclWinTime.c --
 *
 *	Contains Windows specific versions of Tcl functions that
 *	obtain time values from the operating system.
 *
 * Copyright 1995-1998 by Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWinTime.c,v 1.18.2.2 2003/08/27 21:07:22 dgp Exp $
 */

#include "tclWinInt.h"

#define SECSPERDAY (60L * 60L * 24L)
#define SECSPERYEAR (SECSPERDAY * 365L)
#define SECSPER4YEAR (SECSPERYEAR * 4L + SECSPERDAY)











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* 
 * tclWinTime.c --
 *
 *	Contains Windows specific versions of Tcl functions that
 *	obtain time values from the operating system.
 *
 * Copyright 1995-1998 by Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 * RCS: @(#) $Id: tclWinTime.c,v 1.18.2.3 2004/02/07 05:48:12 dgp Exp $
 */

#include "tclWinInt.h"

#define SECSPERDAY (60L * 60L * 24L)
#define SECSPERYEAR (SECSPERDAY * 365L)
#define SECSPER4YEAR (SECSPERYEAR * 4L + SECSPERDAY)
557
558
559
560
561
562
563












564

565
566
567
568
569
570
571

	/*
	 * If we are in the valid range, let the C run-time library
	 * handle it.  Otherwise we need to fake it.  Note that this
	 * algorithm ignores daylight savings time before the epoch.
	 */













	if (*tp >= 0) {

	    return localtime(tp);
	}

	time = *tp - timezone;
	
	/*
	 * If we aren't near to overflowing the long, just add the bias and







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

>







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

	/*
	 * If we are in the valid range, let the C run-time library
	 * handle it.  Otherwise we need to fake it.  Note that this
	 * algorithm ignores daylight savings time before the epoch.
	 */

	/*
	  Hm, Borland's localtime manages to return NULL under certain
	  circumstances (e.g. wintime.test, test 1.2). Nobody tests for this,
	  since 'localtime' isn't supposed to do this, possibly leading to
	  crashes.
	  Patch: We only call this function if we are at least one day into
	  the epoch, else we handle it ourselves (like we do for times < 0).
	  H. Giese, June 2003
	*/
#ifdef __BORLANDC__
	if (*tp >= SECSPERDAY) {
#else
	if (*tp >= 0) {
#endif
	    return localtime(tp);
	}

	time = *tp - timezone;
	
	/*
	 * If we aren't near to overflowing the long, just add the bias and
Changes to win/tclsh.rc.
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
// RCS: @(#) $Id: tclsh.rc,v 1.8 2002/06/18 00:12:24 davygrvy Exp $
//
// Version Resource Script
//

#include <winver.h>
#include <tcl.h>

//
// build-up the name suffix that defines the type of build this is.
//
#ifdef TCL_THREADS
#define SUFFIX_THREADS	    "t"
#else
#define SUFFIX_THREADS	    ""
#endif

#ifdef STATIC_BUILD
#define SUFFIX_STATIC	    "s"
#else
#define SUFFIX_STATIC	    ""
#endif

#ifdef DEBUG
#define SUFFIX_DEBUG	    "d"
#else
#define SUFFIX_DEBUG	    ""
#endif

#define SUFFIX		    SUFFIX_THREADS SUFFIX_STATIC SUFFIX_DEBUG


|










|





|





|
|







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
// RCS: @(#) $Id: tclsh.rc,v 1.8.4.1 2004/02/07 05:48:12 dgp Exp $
//
// Version Resource Script
//

#include <winver.h>
#include <tcl.h>

//
// build-up the name suffix that defines the type of build this is.
//
#if TCL_THREADS
#define SUFFIX_THREADS	    "t"
#else
#define SUFFIX_THREADS	    ""
#endif

#if STATIC_BUILD
#define SUFFIX_STATIC	    "s"
#else
#define SUFFIX_STATIC	    ""
#endif

#if DEBUG
#define SUFFIX_DEBUG	    "g"
#else
#define SUFFIX_DEBUG	    ""
#endif

#define SUFFIX		    SUFFIX_THREADS SUFFIX_STATIC SUFFIX_DEBUG


46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
 FILESUBTYPE 	0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904b0"
        BEGIN
            VALUE "FileDescription", "Tclsh Application\0"
            VALUE "OriginalFilename", "tclsh" STRINGIFY(JOIN(TCL_MAJOR_VERSION,TCL_MINOR_VERSION)) SUFFIX ".exe\0"
            VALUE "CompanyName", "ActiveState Corporation\0"
            VALUE "FileVersion", TCL_PATCH_LEVEL
            VALUE "LegalCopyright", "Copyright \251 2000 by ActiveState Corporation, et al\0"
            VALUE "ProductName", "Tcl " TCL_VERSION " for Windows\0"
            VALUE "ProductVersion", TCL_PATCH_LEVEL
        END
    END







|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
 FILESUBTYPE 	0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904b0"
        BEGIN
            VALUE "FileDescription", "Tclsh Application\0"
            VALUE "OriginalFilename", "tclsh" STRINGIFY(TCL_MAJOR_VERSION) STRINGIFY(TCL_MINOR_VERSION) SUFFIX ".exe\0"
            VALUE "CompanyName", "ActiveState Corporation\0"
            VALUE "FileVersion", TCL_PATCH_LEVEL
            VALUE "LegalCopyright", "Copyright \251 2000 by ActiveState Corporation, et al\0"
            VALUE "ProductName", "Tcl " TCL_VERSION " for Windows\0"
            VALUE "ProductVersion", TCL_PATCH_LEVEL
        END
    END