Tcl Source Code

Check-in [5f6508a146]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

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

Overview
Comment:merge novem
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | novem-purge-literals
Files: files | file ages | folders
SHA3-256: 5f6508a146079ed25a5de4f8d236161772093a0b72ec802ebcb6486b70f4c18d
User & Date: dgp 2019-06-17 18:38:27
Context
2019-06-17
18:38
merge novem Leaf check-in: 5f6508a146 user: dgp tags: novem-purge-literals
18:25
merge trunk check-in: 7877b6c734 user: dgp tags: novem
2019-06-12
19:34
merge novem check-in: a72a317ba0 user: dgp tags: novem-purge-literals
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to doc/binary.n.

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
...
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
...
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
...
389
390
391
392
393
394
395
396

397
398
399

400


401

402
403
404
405
406
407
408
...
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
...
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
...
794
795
796
797
798
799
800
801

802
803
804

805
806
807
808
809
810
811
...
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
.TH binary n 8.0 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
binary \- Insert and extract fields from binary strings
.SH SYNOPSIS
.VS 8.6
\fBbinary decode \fIformat\fR ?\fI\-option value ...\fR? \fIdata\fR
.br
\fBbinary encode \fIformat\fR ?\fI\-option value ...\fR? \fIdata\fR
.br
.VE 8.6
\fBbinary format \fIformatString \fR?\fIarg arg ...\fR?
.br
\fBbinary scan \fIstring formatString \fR?\fIvarName varName ...\fR?
.BE
.SH DESCRIPTION
.PP
This command provides facilities for manipulating binary data.  The
subcommand \fBbinary format\fR creates a binary string from normal
Tcl values.  For example, given the values 16 and 22, on a 32-bit
architecture, it might produce an 8-byte binary string consisting of
two 4-byte integers, one for each of the numbers.  The subcommand
\fBbinary scan\fR, does the opposite: it extracts data
from a binary string and returns it as ordinary Tcl string values.
.VS 8.6
The \fBbinary encode\fR and \fBbinary decode\fR subcommands convert
binary data to or from string encodings such as base64 (used in MIME
messages for example).
.VE 8.6
.PP
Note that other operations on binary data, such as taking a subsequence of it,
getting its length, or reinterpreting it as a string in some encoding, are
done by other Tcl commands (respectively \fBstring range\fR,
\fBstring length\fR and \fBencoding convertfrom\fR in the example cases).  A
binary string in Tcl is merely one where all the characters it contains are in
the range \eu0000\-\eu00FF.
.SH "BINARY ENCODE AND DECODE"
.VS 8.6
.PP
When encoding binary data as a readable string, the starting binary data is
passed to the \fBbinary encode\fR command, together with the name of the
encoding to use and any encoding-specific options desired. Data which has been
encoded can be converted back to binary form using \fBbinary decode\fR. The
following formats and options are supported.
.TP
................................................................................
.
Instructs the decoder to throw an error if it encounters unexpected whitespace
characters. Otherwise it ignores them.
.PP
Note that neither the encoder nor the decoder handle the header and footer of
the uuencode format.
.RE
.VE 8.6
.SH "BINARY FORMAT"
.PP
The \fBbinary format\fR command generates a binary string whose layout
is specified by the \fIformatString\fR and whose contents come from
the additional arguments.  The resulting binary value is returned.
.PP
The \fIformatString\fR consists of a sequence of zero or more field
................................................................................
specifiers separated by zero or more spaces.  Each field specifier is
a single type character followed by an optional flag character followed
by an optional numeric \fIcount\fR.
Most field specifiers consume one argument to obtain the value to be
formatted.  The type character specifies how the value is to be
formatted.  The \fIcount\fR typically indicates how many items of the
specified type are taken from the value.  If present, the \fIcount\fR
is a non-negative decimal integer or \fB*\fR, which normally indicates


that all of the items in the value are to be used.  If the number of
arguments does not match the number of fields in the format string
that consume arguments, then an error is generated. The flag character
is ignored for \fBbinary format\fR.
.PP
Here is a small example to clarify the relation between the field
specifiers and the arguments:

.CS
\fBbinary format\fR d3d {1.0 2.0 3.0 4.0} 0.1
.CE
.PP
The first argument is a list of four numbers, but because of the count
of 3 for the associated field specifier, only the first three will be
used. The second argument is associated with the second field
................................................................................
the \fBencoding convertto\fR command should be used first to change
the string into an external representation
if this truncation is not desired (i.e. if the characters are
not part of the ISO 8859\-1 character set.)
If \fIarg\fR has fewer than \fIcount\fR bytes, then additional zero
bytes are used to pad out the field.  If \fIarg\fR is longer than the
specified length, the extra characters will be ignored.  If


\fIcount\fR is \fB*\fR, then all of the bytes in \fIarg\fR will be
formatted.  If \fIcount\fR is omitted, then one character will be
formatted.  For example,
.RS

.CS
\fBbinary format\fR a7a*a alpha bravo charlie
.CE




will return a string equivalent to \fBalpha\e000\e000bravoc\fR,




.CS
\fBbinary format\fR a* [encoding convertto utf-8 \eu20ac]
.CE




will return a string equivalent to \fB\e342\e202\e254\fR (which is the



UTF-8 byte sequence for a Euro-currency character) and

.CS
\fBbinary format\fR a* [encoding convertto iso8859-15 \eu20ac]
.CE







will return a string equivalent to \fB\e244\fR (which is the ISO
8859\-15 byte sequence for a Euro-currency character). Contrast these
last two with:

.CS
\fBbinary format\fR a* \eu20ac
.CE







which returns a string equivalent to \fB\e254\fR (i.e. \fB\exac\fR) by
truncating the high-bits of the character, and which is probably not
what is desired.
.RE
.IP \fBA\fR 5
This form is the same as \fBa\fR except that spaces are used for
padding instead of nulls.  For example,
.RS

.CS
\fBbinary format\fR A6A*A alpha bravo charlie
.CE




will return \fBalpha bravoc\fR.

.RE
.IP \fBb\fR 5
Stores a string of \fIcount\fR binary digits in low-to-high order
within each byte in the output string.  \fIArg\fR must contain a
sequence of \fB1\fR and \fB0\fR characters.  The resulting bytes are
emitted in first to last order with the bits being formatted in
low-to-high order within each byte.  If \fIarg\fR has fewer than
\fIcount\fR digits, then zeros will be used for the remaining bits.
If \fIarg\fR has more than the specified number of digits, the extra
digits will be ignored.  If \fIcount\fR is \fB*\fR, then all of the


digits in \fIarg\fR will be formatted.  If \fIcount\fR is omitted,
then one digit will be formatted.  If the number of bits formatted
does not end at a byte boundary, the remaining bits of the last byte
will be zeros.  For example,
.RS

.CS
\fBbinary format\fR b5b* 11100 111000011010
.CE




will return a string equivalent to \fB\ex07\ex87\ex05\fR.

.RE
.IP \fBB\fR 5
This form is the same as \fBb\fR except that the bits are stored in
high-to-low order within each byte.  For example,
.RS

.CS
\fBbinary format\fR B5B* 11100 111000011010
.CE




will return a string equivalent to \fB\exe0\exe1\exa0\fR.

.RE
.IP \fBH\fR 5
Stores a string of \fIcount\fR hexadecimal digits in high-to-low
within each byte in the output string.  \fIArg\fR must contain a
sequence of characters in the set
.QW 0123456789abcdefABCDEF .
The resulting bytes are emitted in first to last order with the hex digits
being formatted in high-to-low order within each byte.  If \fIarg\fR
has fewer than \fIcount\fR digits, then zeros will be used for the
remaining digits.  If \fIarg\fR has more than the specified number of
digits, the extra digits will be ignored.  If \fIcount\fR is

\fB*\fR, then all of the digits in \fIarg\fR will be formatted.  If
\fIcount\fR is omitted, then one digit will be formatted.  If the
number of digits formatted does not end at a byte boundary, the
remaining bits of the last byte will be zeros.  For example,
.RS

.CS
\fBbinary format\fR H3H*H2 ab DEF 987
.CE




will return a string equivalent to \fB\exab\ex00\exde\exf0\ex98\fR.

.RE
.IP \fBh\fR 5
This form is the same as \fBH\fR except that the digits are stored in
low-to-high order within each byte. This is seldom required. For example,
.RS

.CS
\fBbinary format\fR h3h*h2 AB def 987
.CE




will return a string equivalent to \fB\exba\ex00\exed\ex0f\ex89\fR.

.RE
.IP \fBc\fR 5
Stores one or more 8-bit integer values in the output string.  If no
\fIcount\fR is specified, then \fIarg\fR must consist of an integer
value. If \fIcount\fR is specified, \fIarg\fR must consist of a list
containing at least that many integers. The low-order 8 bits of each integer
are stored as a one-byte value at the cursor position.  If \fIcount\fR

is \fB*\fR, then all of the integers in the list are formatted. If the
number of elements in the list is greater
than \fIcount\fR, then the extra elements are ignored.  For example,
.RS

.CS
\fBbinary format\fR c3cc* {3 -3 128 1} 260 {2 5}
.CE

will return a string equivalent to


\fB\ex03\exfd\ex80\ex04\ex02\ex05\fR, whereas




.CS
\fBbinary format\fR c {2 5}
.CE

will generate an error.
.RE
.IP \fBs\fR 5
This form is the same as \fBc\fR except that it stores one or more
16-bit integers in little-endian byte order in the output string.  The
low-order 16-bits of each integer are stored as a two-byte value at
the cursor position with the least significant byte stored first.  For
example,
.RS

.CS
\fBbinary format\fR s3 {3 -3 258 1}
.CE

will return a string equivalent to


\fB\ex03\ex00\exfd\exff\ex02\ex01\fR.

.RE
.IP \fBS\fR 5
This form is the same as \fBs\fR except that it stores one or more
16-bit integers in big-endian byte order in the output string.  For
example,
.RS

.CS
\fBbinary format\fR S3 {3 -3 258 1}
.CE

will return a string equivalent to


\fB\ex00\ex03\exff\exfd\ex01\ex02\fR.

.RE
.IP \fBt\fR 5
This form (mnemonically \fItiny\fR) is the same as \fBs\fR and \fBS\fR
except that it stores the 16-bit integers in the output string in the
native byte order of the machine where the Tcl script is running.
To determine what the native byte order of the machine is, refer to
the \fBbyteOrder\fR element of the \fBtcl_platform\fR array.
.IP \fBi\fR 5
This form is the same as \fBc\fR except that it stores one or more
32-bit integers in little-endian byte order in the output string.  The
low-order 32-bits of each integer are stored as a four-byte value at
the cursor position with the least significant byte stored first.  For
example,
.RS

.CS
\fBbinary format\fR i3 {3 -3 65536 1}
.CE

will return a string equivalent to


\fB\ex03\ex00\ex00\ex00\exfd\exff\exff\exff\ex00\ex00\ex01\ex00\fR

.RE
.IP \fBI\fR 5
This form is the same as \fBi\fR except that it stores one or more one
or more 32-bit integers in big-endian byte order in the output string.
For example,
.RS

.CS
\fBbinary format\fR I3 {3 -3 65536 1}
.CE

will return a string equivalent to


\fB\ex00\ex00\ex00\ex03\exff\exff\exff\exfd\ex00\ex01\ex00\ex00\fR

.RE
.IP \fBn\fR 5
This form (mnemonically \fInumber\fR or \fInormal\fR) is the same as
\fBi\fR and \fBI\fR except that it stores the 32-bit integers in the
output string in the native byte order of the machine where the Tcl
script is running.
To determine what the native byte order of the machine is, refer to
................................................................................
the \fBbyteOrder\fR element of the \fBtcl_platform\fR array.
.IP \fBw\fR 5
This form is the same as \fBc\fR except that it stores one or more
64-bit integers in little-endian byte order in the output string.  The
low-order 64-bits of each integer are stored as an eight-byte value at
the cursor position with the least significant byte stored first.  For
example,
.RS

.CS
\fBbinary format\fR w 7810179016327718216
.CE

will return the string \fBHelloTcl\fR
.RE
.IP \fBW\fR 5
This form is the same as \fBw\fR except that it stores one or more one
or more 64-bit integers in big-endian byte order in the output string.
For example,
.RS

.CS
\fBbinary format\fR Wc 4785469626960341345 110
.CE

will return the string \fBBigEndian\fR
.RE
.IP \fBm\fR 5
This form (mnemonically the mirror of \fBw\fR) is the same as \fBw\fR
and \fBW\fR except that it stores the 64-bit integers in the output
string in the native byte order of the machine where the Tcl script is
running.
To determine what the native byte order of the machine is, refer to
................................................................................
point number may vary across architectures, so the number of bytes
that are generated may vary.  If the value overflows the
machine's native representation, then the value of FLT_MAX
as defined by the system will be used instead.  Because Tcl uses
double-precision floating point numbers internally, there may be some
loss of precision in the conversion to single-precision.  For example,
on a Windows system running on an Intel Pentium processor,
.RS

.CS
\fBbinary format\fR f2 {1.6 3.4}
.CE

will return a string equivalent to


\fB\excd\excc\excc\ex3f\ex9a\ex99\ex59\ex40\fR.

.RE
.IP \fBr\fR 5
This form (mnemonically \fIreal\fR) is the same as \fBf\fR except that
it stores the single-precision floating point numbers in little-endian
order.  This conversion only produces meaningful output when used on
machines which use the IEEE floating point representation (very
common, but not universal.)
................................................................................
This form is the same as \fBr\fR except that it stores the
single-precision floating point numbers in big-endian order.
.IP \fBd\fR 5
This form is the same as \fBf\fR except that it stores one or more one
or more double-precision floating point numbers in the machine's native
representation in the output string.  For example, on a
Windows system running on an Intel Pentium processor,
.RS

.CS
\fBbinary format\fR d1 {1.6}
.CE

will return a string equivalent to


\fB\ex9a\ex99\ex99\ex99\ex99\ex99\exf9\ex3f\fR.

.RE
.IP \fBq\fR 5
This form (mnemonically the mirror of \fBd\fR) is the same as \fBd\fR
except that it stores the double-precision floating point numbers in
little-endian order.  This conversion only produces meaningful output
when used on machines which use the IEEE floating point representation
(very common, but not universal.)
.IP \fBQ\fR 5
This form is the same as \fBq\fR except that it stores the
double-precision floating point numbers in big-endian order.
.IP \fBx\fR 5
Stores \fIcount\fR null bytes in the output string.  If \fIcount\fR is
not specified, stores one null byte.  If \fIcount\fR is \fB*\fR,

generates an error.  This type does not consume an argument.  For
example,
.RS

.CS
\fBbinary format\fR a3xa3x2a3 abc def ghi
.CE




will return a string equivalent to \fBabc\e000def\e000\e000ghi\fR.

.RE
.IP \fBX\fR 5
Moves the cursor back \fIcount\fR bytes in the output string.  If


\fIcount\fR is \fB*\fR or is larger than the current cursor position,
then the cursor is positioned at location 0 so that the next byte
stored will be the first byte in the result string.  If \fIcount\fR is
omitted then the cursor is moved back one byte.  This type does not
consume an argument.  For example,
.RS

.CS
\fBbinary format\fR a3X*a3X2a3 abc def ghi
.CE

will return \fBdghi\fR.
.RE
.IP \[email protected]\fR 5
Moves the cursor to the absolute location in the output string
specified by \fIcount\fR.  Position 0 refers to the first byte in the
output string.  If \fIcount\fR refers to a position beyond the last
byte stored so far, then null bytes will be placed in the uninitialized
locations and the cursor will be placed at the specified location.  If


\fIcount\fR is \fB*\fR, then the cursor is moved to the current end of
the output string.  If \fIcount\fR is omitted, then an error will be
generated.  This type does not consume an argument. For example,
.RS

.CS
\fBbinary format\fR [email protected]@*[email protected] abcde f ghi j
.CE




will return \fBabfdeghi\e000\e000j\fR.

.RE
.SH "BINARY SCAN"
.PP
The \fBbinary scan\fR command parses fields from a binary string,
returning the number of conversions performed.  \fIString\fR gives the
input bytes to be parsed (one byte per character, and characters not
representable as a byte have their high bits chopped)
................................................................................
spaces.  Each field specifier is a single type character followed by
an optional flag character followed by an optional numeric \fIcount\fR.
Most field specifiers consume one
argument to obtain the variable into which the scanned values should
be placed.  The type character specifies how the binary data is to be
interpreted.  The \fIcount\fR typically indicates how many items of
the specified type are taken from the data.  If present, the
\fIcount\fR is a non-negative decimal integer or \fB*\fR, which

normally indicates that all of the remaining items in the data are to
be used.  If there are not enough bytes left after the current cursor
position to satisfy the current field specifier, then the
corresponding variable is left untouched and \fBbinary scan\fR returns
immediately with the number of variables that were set.  If there are
not enough arguments for all of the fields in the format string that
consume arguments, then an error is generated. The flag character
.QW u
may be given to cause some types to be read as unsigned values. The flag
is accepted for all field types but is ignored for non-integer fields.
.PP
A similar example as with \fBbinary format\fR should explain the
relation between field specifiers and arguments in case of the binary
scan subcommand:

.CS
\fBbinary scan\fR $bytes s3s first second
.CE
.PP
This command (provided the binary string in the variable \fIbytes\fR
is long enough) assigns a list of three integers to the variable
\fIfirst\fR and assigns a single value to the variable \fIsecond\fR.
If \fIbytes\fR contains fewer than 8 bytes (i.e. four 2-byte
integers), no assignment to \fIsecond\fR will be made, and if
\fIbytes\fR contains fewer than 6 bytes (i.e. three 2-byte integers),
no assignment to \fIfirst\fR will be made.  Hence:

.CS
puts [\fBbinary scan\fR abcdefg s3s first second]
puts $first
puts $second
.CE

will print (assuming neither variable is set previously):

.CS
1
25185 25699 26213
can't read "second": no such variable
.CE
.PP
It is \fIimportant\fR to note that the \fBc\fR, \fBs\fR, and \fBS\fR
(and \fBi\fR and \fBI\fR on 64bit systems) will be scanned into
long data size values.  In doing this, values that have their high
bit set (0x80 for chars, 0x8000 for shorts, 0x80000000 for ints),
will be sign extended.  Thus the following will occur:

.CS
set signShort [\fBbinary format\fR s1 0x8000]
\fBbinary scan\fR $signShort s1 val; \fI# val == 0xFFFF8000\fR
.CE

If you require unsigned values you can include the
.QW u
flag character following
the field type. For example, to read an unsigned short value:

.CS
set signShort [\fBbinary format\fR s1 0x8000]
\fBbinary scan\fR $signShort su1 val; \fI# val == 0x00008000\fR
.CE
.PP
Each type-count pair moves an imaginary cursor through the binary data,
reading bytes from the current position.  The cursor is initially
at position 0 at the beginning of the data.  The type may be any one of
the following characters:
.IP \fBa\fR 5
The data is a byte string of length \fIcount\fR.  If \fIcount\fR

is \fB*\fR, then all of the remaining bytes in \fIstring\fR will be
scanned into the variable.  If \fIcount\fR is omitted, then one
byte will be scanned.
All bytes scanned will be interpreted as being characters in the
range \eu0000-\eu00ff so the \fBencoding convertfrom\fR command will be
needed if the string is not a binary string or a string encoded in ISO
8859\-1.
For example,
.RS

.CS
\fBbinary scan\fR abcde\e000fghi a6a10 var1 var2
.CE

will return \fB1\fR with the string equivalent to \fBabcde\e000\fR
stored in \fIvar1\fR and \fIvar2\fR left unmodified, and

.CS
\fBbinary scan\fR \e342\e202\e254 a* var1
set var2 [encoding convertfrom utf-8 $var1]
.CE

will store a Euro-currency character in \fIvar2\fR.
.RE
.IP \fBA\fR 5
This form is the same as \fBa\fR, except trailing blanks and nulls are stripped from
the scanned value before it is stored in the variable.  For example,
.RS

.CS
\fBbinary scan\fR "abc efghi  \e000" A* var1
.CE

will return \fB1\fR with \fBabc efghi\fR stored in \fIvar1\fR.
.RE
.IP \fBb\fR 5
The data is turned into a string of \fIcount\fR binary digits in
low-to-high order represented as a sequence of
.QW 1
and
.QW 0
characters.  The data bytes are scanned in first to last order with
the bits being taken in low-to-high order within each byte.  Any extra
bits in the last byte are ignored.  If \fIcount\fR is \fB*\fR, then

all of the remaining bits in \fIstring\fR will be scanned.  If
\fIcount\fR is omitted, then one bit will be scanned.  For example,
.RS

.CS
\fBbinary scan\fR \ex07\ex87\ex05 b5b* var1 var2
.CE

will return \fB2\fR with \fB11100\fR stored in \fIvar1\fR and
\fB1110000110100000\fR stored in \fIvar2\fR.
.RE
.IP \fBB\fR 5
This form is the same as \fBb\fR, except the bits are taken in
high-to-low order within each byte.  For example,
.RS

.CS
\fBbinary scan\fR \ex70\ex87\ex05 B5B* var1 var2
.CE

will return \fB2\fR with \fB01110\fR stored in \fIvar1\fR and
\fB1000011100000101\fR stored in \fIvar2\fR.
.RE
.IP \fBH\fR 5
The data is turned into a string of \fIcount\fR hexadecimal digits in
high-to-low order represented as a sequence of characters in the set
.QW 0123456789abcdef .
The data bytes are scanned in first to last
order with the hex digits being taken in high-to-low order within each
byte. Any extra bits in the last byte are ignored. If \fIcount\fR is

\fB*\fR, then all of the remaining hex digits in \fIstring\fR will be
scanned. If \fIcount\fR is omitted, then one hex digit will be
scanned. For example,
.RS

.CS
\fBbinary scan\fR \ex07\exC6\ex05\ex1f\ex34 H3H* var1 var2
.CE

will return \fB2\fR with \fB07c\fR stored in \fIvar1\fR and
\fB051f34\fR stored in \fIvar2\fR.
.RE
.IP \fBh\fR 5
This form is the same as \fBH\fR, except the digits are taken in
reverse (low-to-high) order within each byte. For example,
.RS

.CS
\fBbinary scan\fR \ex07\ex86\ex05\ex12\ex34 h3h* var1 var2
.CE

will return \fB2\fR with \fB706\fR stored in \fIvar1\fR and
\fB502143\fR stored in \fIvar2\fR.
.PP
Note that most code that wishes to parse the hexadecimal digits from
multiple bytes in order should use the \fBH\fR format.
.RE
.IP \fBc\fR 5
The data is turned into \fIcount\fR 8-bit signed integers and stored
in the corresponding variable as a list. If \fIcount\fR is \fB*\fR,


then all of the remaining bytes in \fIstring\fR will be scanned.  If
\fIcount\fR is omitted, then one 8-bit integer will be scanned.  For
example,
.RS

.CS
\fBbinary scan\fR \ex07\ex86\ex05 c2c* var1 var2
.CE

will return \fB2\fR with \fB7 -122\fR stored in \fIvar1\fR and \fB5\fR
stored in \fIvar2\fR.  Note that the integers returned are signed, but
they can be converted to unsigned 8-bit quantities using an expression
like:
.CS
set num [expr { $num & 0xff }]
.CE

.RE
.IP \fBs\fR 5
The data is interpreted as \fIcount\fR 16-bit signed integers
represented in little-endian byte order.  The integers are stored in

the corresponding variable as a list.  If \fIcount\fR is \fB*\fR, then

all of the remaining bytes in \fIstring\fR will be scanned.  If
\fIcount\fR is omitted, then one 16-bit integer will be scanned.  For
example,
.RS

.CS
\fBbinary scan\fR \ex05\ex00\ex07\ex00\exf0\exff s2s* var1 var2
.CE

will return \fB2\fR with \fB5 7\fR stored in \fIvar1\fR and \fB\-16\fR
stored in \fIvar2\fR.  Note that the integers returned are signed, but
they can be converted to unsigned 16-bit quantities using an expression
like:
.CS
set num [expr { $num & 0xffff }]
.CE

.RE
.IP \fBS\fR 5
This form is the same as \fBs\fR except that the data is interpreted
as \fIcount\fR 16-bit signed integers represented in big-endian byte
order.  For example,
.RS

.CS
\fBbinary scan\fR \ex00\ex05\ex00\ex07\exff\exf0 S2S* var1 var2
.CE

will return \fB2\fR with \fB5 7\fR stored in \fIvar1\fR and \fB\-16\fR
stored in \fIvar2\fR.
.RE
.IP \fBt\fR 5
The data is interpreted as \fIcount\fR 16-bit signed integers
represented in the native byte order of the machine running the Tcl

script.  It is otherwise identical to \fBs\fR and \fBS\fR.
To determine what the native byte order of the machine is, refer to
the \fBbyteOrder\fR element of the \fBtcl_platform\fR array.
.IP \fBi\fR 5
The data is interpreted as \fIcount\fR 32-bit signed integers
represented in little-endian byte order.  The integers are stored in

the corresponding variable as a list.  If \fIcount\fR is \fB*\fR, then

all of the remaining bytes in \fIstring\fR will be scanned.  If
\fIcount\fR is omitted, then one 32-bit integer will be scanned.  For
example,
.RS

.CS
set str \ex05\ex00\ex00\ex00\ex07\ex00\ex00\ex00\exf0\exff\exff\exff
\fBbinary scan\fR $str i2i* var1 var2
.CE

will return \fB2\fR with \fB5 7\fR stored in \fIvar1\fR and \fB\-16\fR
stored in \fIvar2\fR.  Note that the integers returned are signed, but
they can be converted to unsigned 32-bit quantities using an expression
like:
.CS
set num [expr { $num & 0xffffffff }]
.CE
.RE
.IP \fBI\fR 5
This form is the same as \fBI\fR except that the data is interpreted
as \fIcount\fR 32-bit signed integers represented in big-endian byte

order.  For example,
.RS

.CS
set str \ex00\ex00\ex00\ex05\ex00\ex00\ex00\ex07\exff\exff\exff\exf0
\fBbinary scan\fR $str I2I* var1 var2
.CE

will return \fB2\fR with \fB5 7\fR stored in \fIvar1\fR and \fB\-16\fR
stored in \fIvar2\fR.
.RE
.IP \fBn\fR 5
The data is interpreted as \fIcount\fR 32-bit signed integers
represented in the native byte order of the machine running the Tcl

script.  It is otherwise identical to \fBi\fR and \fBI\fR.
To determine what the native byte order of the machine is, refer to
the \fBbyteOrder\fR element of the \fBtcl_platform\fR array.
.IP \fBw\fR 5
The data is interpreted as \fIcount\fR 64-bit signed integers
represented in little-endian byte order.  The integers are stored in

the corresponding variable as a list.  If \fIcount\fR is \fB*\fR, then

all of the remaining bytes in \fIstring\fR will be scanned.  If
\fIcount\fR is omitted, then one 64-bit integer will be scanned.  For
example,
.RS

.CS
set str \ex05\ex00\ex00\ex00\ex07\ex00\ex00\ex00\exf0\exff\exff\exff
\fBbinary scan\fR $str wi* var1 var2
.CE

will return \fB2\fR with \fB30064771077\fR stored in \fIvar1\fR and
\fB\-16\fR stored in \fIvar2\fR.  Note that the integers returned are
signed and cannot be represented by Tcl as unsigned values.
.RE
.IP \fBW\fR 5
This form is the same as \fBw\fR except that the data is interpreted
as \fIcount\fR 64-bit signed integers represented in big-endian byte

order.  For example,
.RS

.CS
set str \ex00\ex00\ex00\ex05\ex00\ex00\ex00\ex07\exff\exff\exff\exf0
\fBbinary scan\fR $str WI* var1 var2
.CE

will return \fB2\fR with \fB21474836487\fR stored in \fIvar1\fR and \fB\-16\fR
stored in \fIvar2\fR.
.RE
.IP \fBm\fR 5
The data is interpreted as \fIcount\fR 64-bit signed integers
represented in the native byte order of the machine running the Tcl

script.  It is otherwise identical to \fBw\fR and \fBW\fR.
To determine what the native byte order of the machine is, refer to
the \fBbyteOrder\fR element of the \fBtcl_platform\fR array.
.IP \fBf\fR 5
The data is interpreted as \fIcount\fR single-precision floating point
numbers in the machine's native representation.  The floating point
numbers are stored in the corresponding variable as a list.  If


\fIcount\fR is \fB*\fR, then all of the remaining bytes in
\fIstring\fR will be scanned.  If \fIcount\fR is omitted, then one
single-precision floating point number will be scanned.  The size of a
floating point number may vary across architectures, so the number of
bytes that are scanned may vary.  If the data does not represent a
valid floating point number, the resulting value is undefined and
compiler dependent.  For example, on a Windows system running on an
Intel Pentium processor,
.RS

.CS
\fBbinary scan\fR \ex3f\excc\excc\excd f var1
.CE

will return \fB1\fR with \fB1.6000000238418579\fR stored in
\fIvar1\fR.
.RE
.IP \fBr\fR 5
This form is the same as \fBf\fR except that the data is interpreted
as \fIcount\fR single-precision floating point number in little-endian
order.  This conversion is not portable to the minority of systems not
................................................................................
order.  This conversion is not portable to the minority of systems not
using IEEE floating point representations.
.IP \fBd\fR 5
This form is the same as \fBf\fR except that the data is interpreted
as \fIcount\fR double-precision floating point numbers in the
machine's native representation. For example, on a Windows system
running on an Intel Pentium processor,
.RS

.CS
\fBbinary scan\fR \ex9a\ex99\ex99\ex99\ex99\ex99\exf9\ex3f d var1
.CE

will return \fB1\fR with \fB1.6000000000000001\fR
stored in \fIvar1\fR.
.RE
.IP \fBq\fR 5
This form is the same as \fBd\fR except that the data is interpreted
as \fIcount\fR double-precision floating point number in little-endian
order.  This conversion is not portable to the minority of systems not
................................................................................
.IP \fBQ\fR 5
This form is the same as \fBd\fR except that the data is interpreted
as \fIcount\fR double-precision floating point number in big-endian
order.  This conversion is not portable to the minority of systems not
using IEEE floating point representations.
.IP \fBx\fR 5
Moves the cursor forward \fIcount\fR bytes in \fIstring\fR.  If


\fIcount\fR is \fB*\fR or is larger than the number of bytes after the
current cursor position, then the cursor is positioned after
the last byte in \fIstring\fR.  If \fIcount\fR is omitted, then the
cursor is moved forward one byte.  Note that this type does not
consume an argument.  For example,
.RS

.CS
\fBbinary scan\fR \ex01\ex02\ex03\ex04 x2H* var1
.CE

will return \fB1\fR with \fB0304\fR stored in \fIvar1\fR.
.RE
.IP \fBX\fR 5
Moves the cursor back \fIcount\fR bytes in \fIstring\fR.  If


\fIcount\fR is \fB*\fR or is larger than the current cursor position,
then the cursor is positioned at location 0 so that the next byte
scanned will be the first byte in \fIstring\fR.  If \fIcount\fR
is omitted then the cursor is moved back one byte.  Note that this
type does not consume an argument.  For example,
.RS

.CS
\fBbinary scan\fR \ex01\ex02\ex03\ex04 c2XH* var1 var2
.CE

will return \fB2\fR with \fB1 2\fR stored in \fIvar1\fR and \fB020304\fR
stored in \fIvar2\fR.
.RE
.IP \[email protected]\fR 5
Moves the cursor to the absolute location in the data string specified
by \fIcount\fR.  Note that position 0 refers to the first byte in
\fIstring\fR.  If \fIcount\fR refers to a position beyond the end of
\fIstring\fR, then the cursor is positioned after the last byte.  If
\fIcount\fR is omitted, then an error will be generated.  For example,
.RS

.CS
\fBbinary scan\fR \ex01\ex02\ex03\ex04 [email protected]* var1 var2
.CE

will return \fB2\fR with \fB1 2\fR stored in \fIvar1\fR and \fB020304\fR
stored in \fIvar2\fR.
.RE
.SH "PORTABILITY ISSUES"
.PP
The \fBr\fR, \fBR\fR, \fBq\fR and \fBQ\fR conversions will only work
reliably for transferring data between computers which are all using






<




<













<



<








<







 







<







 







|
>
>







>







 







>
>
|

|
|
>


|
>
>
>
>
|
>
>
>
>


|
>
>
>
>
|
>
>
>
|
>


|
>
>
>
>
>
>
>
|

|
>


|
>
>
>
>
>
>
>
|






|
>


|
>
>
>
>
|
>



|





|
>
>




|
>


|
>
>
>
>
|
>




|
>


|
>
>
>
>
|
>



|







>
|



|
>


|
>
>
>
>
|
>




|
>


|
>
>
>
>
|
>






|
>
|


|
>


|
>
|
>
>
|
>
>
>
>


|
>








|
>


|
>
|
>
>
|
>





|
>


|
>
|
>
>
|
>













|
>


|
>
|
>
>

>





|
>


|
>
|
>
>

>







 







|
>


|
>
|





|
>


|
>
|







 







|
>


|
>
|
>
>
|
>







 







|
>


|
>
|
>
>
|
>












|
>


|
>


|
>
>
>
>
|
>



>
>
|




|
>


|
>








>
>
|


|
>


|
>
>
>
>
|
>







 







|
>
|












|
>










|
>




|
>
|
>










|
>



|
>



|
>










|
>
|







|
>


|
>

|
>



|
>





|
>


|
>










|
>
|

|
>


|
>






|
>


|
>










>
|


|
>


|
>






|
>


|
>








|
>
>



|
>


|
>

|
<
<
<
<
<
>



|
>
|
>
|


|
>


|
>

|
<
<
<
<
<
>



|

|
>


|
>






>
|




|
>
|
>
|


|
>



|
>

|
<
|
<
<
<




>
|
|
>



|
>






>
|




|
>
|
>
|


|
>



|
>

|
<




>
|
|
>



|
>






>
|






>
>
|







|
>


|
>







 







|
>


|
>







 







>
>
|




|
>


|
>




>
>
|




|
>


|
>









|
>


|
>







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
...
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
...
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
...
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
...
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
...
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808





809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827





828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867

868



869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909

910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
...
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
...
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
.TH binary n 8.0 Tcl "Tcl Built-In Commands"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
binary \- Insert and extract fields from binary strings
.SH SYNOPSIS

\fBbinary decode \fIformat\fR ?\fI\-option value ...\fR? \fIdata\fR
.br
\fBbinary encode \fIformat\fR ?\fI\-option value ...\fR? \fIdata\fR
.br

\fBbinary format \fIformatString \fR?\fIarg arg ...\fR?
.br
\fBbinary scan \fIstring formatString \fR?\fIvarName varName ...\fR?
.BE
.SH DESCRIPTION
.PP
This command provides facilities for manipulating binary data.  The
subcommand \fBbinary format\fR creates a binary string from normal
Tcl values.  For example, given the values 16 and 22, on a 32-bit
architecture, it might produce an 8-byte binary string consisting of
two 4-byte integers, one for each of the numbers.  The subcommand
\fBbinary scan\fR, does the opposite: it extracts data
from a binary string and returns it as ordinary Tcl string values.

The \fBbinary encode\fR and \fBbinary decode\fR subcommands convert
binary data to or from string encodings such as base64 (used in MIME
messages for example).

.PP
Note that other operations on binary data, such as taking a subsequence of it,
getting its length, or reinterpreting it as a string in some encoding, are
done by other Tcl commands (respectively \fBstring range\fR,
\fBstring length\fR and \fBencoding convertfrom\fR in the example cases).  A
binary string in Tcl is merely one where all the characters it contains are in
the range \eu0000\-\eu00FF.
.SH "BINARY ENCODE AND DECODE"

.PP
When encoding binary data as a readable string, the starting binary data is
passed to the \fBbinary encode\fR command, together with the name of the
encoding to use and any encoding-specific options desired. Data which has been
encoded can be converted back to binary form using \fBbinary decode\fR. The
following formats and options are supported.
.TP
................................................................................
.
Instructs the decoder to throw an error if it encounters unexpected whitespace
characters. Otherwise it ignores them.
.PP
Note that neither the encoder nor the decoder handle the header and footer of
the uuencode format.
.RE

.SH "BINARY FORMAT"
.PP
The \fBbinary format\fR command generates a binary string whose layout
is specified by the \fIformatString\fR and whose contents come from
the additional arguments.  The resulting binary value is returned.
.PP
The \fIformatString\fR consists of a sequence of zero or more field
................................................................................
specifiers separated by zero or more spaces.  Each field specifier is
a single type character followed by an optional flag character followed
by an optional numeric \fIcount\fR.
Most field specifiers consume one argument to obtain the value to be
formatted.  The type character specifies how the value is to be
formatted.  The \fIcount\fR typically indicates how many items of the
specified type are taken from the value.  If present, the \fIcount\fR
is a non-negative decimal integer or
.QW \fB*\fR ,
which normally indicates
that all of the items in the value are to be used.  If the number of
arguments does not match the number of fields in the format string
that consume arguments, then an error is generated. The flag character
is ignored for \fBbinary format\fR.
.PP
Here is a small example to clarify the relation between the field
specifiers and the arguments:
.PP
.CS
\fBbinary format\fR d3d {1.0 2.0 3.0 4.0} 0.1
.CE
.PP
The first argument is a list of four numbers, but because of the count
of 3 for the associated field specifier, only the first three will be
used. The second argument is associated with the second field
................................................................................
the \fBencoding convertto\fR command should be used first to change
the string into an external representation
if this truncation is not desired (i.e. if the characters are
not part of the ISO 8859\-1 character set.)
If \fIarg\fR has fewer than \fIcount\fR bytes, then additional zero
bytes are used to pad out the field.  If \fIarg\fR is longer than the
specified length, the extra characters will be ignored.  If
\fIcount\fR is
.QW \fB*\fR ,
then all of the bytes in \fIarg\fR will be
formatted.  If \fIcount\fR is omitted, then one character will be
formatted.  For example, the command:
.RS 
.PP
.CS
\fBbinary format\fR a7a*a alpha bravo charlie
.CE 
.PP
will return a binary string equivalent to:
.PP
.CS
\fBalpha\e000\e000bravoc\fR
.CE
.PP
the command:
.PP
.CS
\fBbinary format\fR a* [encoding convertto utf-8 \eu20ac]
.CE 
.PP
will return a binary string equivalent to:
.PP
.CS
\fB\e342\e202\e254\fR
.CE
.PP
(which is the
UTF-8 byte sequence for a Euro-currency character), and the command:
.PP
.CS
\fBbinary format\fR a* [encoding convertto iso8859-15 \eu20ac]
.CE 
.PP
will return a binary string equivalent to:
.PP
.CS
\fB\e244\fR
.CE
.PP
(which is the ISO
8859\-15 byte sequence for a Euro-currency character). Contrast these
last two with: 
.PP
.CS
\fBbinary format\fR a* \eu20ac
.CE 
.PP
which returns a binary string equivalent to:
.PP
.CS
\fB\e254\fR
.CE
.PP
(i.e. \fB\exac\fR) by
truncating the high-bits of the character, and which is probably not
what is desired.
.RE
.IP \fBA\fR 5
This form is the same as \fBa\fR except that spaces are used for
padding instead of nulls.  For example,
.RS 
.PP
.CS
\fBbinary format\fR A6A*A alpha bravo charlie
.CE 
.PP
will return
.PP
.CS
\fBalpha bravoc\fR
.CE
.RE
.IP \fBb\fR 5
Stores a string of \fIcount\fR binary digits in low-to-high order
within each byte in the output binary string.  \fIArg\fR must contain a
sequence of \fB1\fR and \fB0\fR characters.  The resulting bytes are
emitted in first to last order with the bits being formatted in
low-to-high order within each byte.  If \fIarg\fR has fewer than
\fIcount\fR digits, then zeros will be used for the remaining bits.
If \fIarg\fR has more than the specified number of digits, the extra
digits will be ignored.  If \fIcount\fR is
.QW \fB*\fR ,
then all of the
digits in \fIarg\fR will be formatted.  If \fIcount\fR is omitted,
then one digit will be formatted.  If the number of bits formatted
does not end at a byte boundary, the remaining bits of the last byte
will be zeros.  For example,
.RS 
.PP
.CS
\fBbinary format\fR b5b* 11100 111000011010
.CE 
.PP
will return a binary string equivalent to:
.PP
.CS
\fB\ex07\ex87\ex05\fR
.CE
.RE
.IP \fBB\fR 5
This form is the same as \fBb\fR except that the bits are stored in
high-to-low order within each byte.  For example,
.RS 
.PP
.CS
\fBbinary format\fR B5B* 11100 111000011010
.CE 
.PP
will return a binary string equivalent to:
.PP
.CS
\fB\exe0\exe1\exa0\fR
.CE
.RE
.IP \fBH\fR 5
Stores a string of \fIcount\fR hexadecimal digits in high-to-low
within each byte in the output binary string.  \fIArg\fR must contain a
sequence of characters in the set
.QW 0123456789abcdefABCDEF .
The resulting bytes are emitted in first to last order with the hex digits
being formatted in high-to-low order within each byte.  If \fIarg\fR
has fewer than \fIcount\fR digits, then zeros will be used for the
remaining digits.  If \fIarg\fR has more than the specified number of
digits, the extra digits will be ignored.  If \fIcount\fR is
.QW \fB*\fR ,
then all of the digits in \fIarg\fR will be formatted.  If
\fIcount\fR is omitted, then one digit will be formatted.  If the
number of digits formatted does not end at a byte boundary, the
remaining bits of the last byte will be zeros.  For example,
.RS 
.PP
.CS
\fBbinary format\fR H3H*H2 ab DEF 987
.CE 
.PP
will return a binary string equivalent to:
.PP
.CS
\fB\exab\ex00\exde\exf0\ex98\fR
.CE
.RE
.IP \fBh\fR 5
This form is the same as \fBH\fR except that the digits are stored in
low-to-high order within each byte. This is seldom required. For example,
.RS 
.PP
.CS
\fBbinary format\fR h3h*h2 AB def 987
.CE 
.PP
will return a binary string equivalent to:
.PP
.CS
\fB\exba\ex00\exed\ex0f\ex89\fR
.CE
.RE
.IP \fBc\fR 5
Stores one or more 8-bit integer values in the output string.  If no
\fIcount\fR is specified, then \fIarg\fR must consist of an integer
value. If \fIcount\fR is specified, \fIarg\fR must consist of a list
containing at least that many integers. The low-order 8 bits of each integer
are stored as a one-byte value at the cursor position.  If \fIcount\fR is
.QW \fB*\fR ,
then all of the integers in the list are formatted. If the
number of elements in the list is greater
than \fIcount\fR, then the extra elements are ignored.  For example,
.RS 
.PP
.CS
\fBbinary format\fR c3cc* {3 -3 128 1} 260 {2 5}
.CE 
.PP
will return a binary string equivalent to:
.PP
.CS
\fB\ex03\exfd\ex80\ex04\ex02\ex05\fR
.CE
.PP
whereas: 
.PP
.CS
\fBbinary format\fR c {2 5}
.CE 
.PP
will generate an error.
.RE
.IP \fBs\fR 5
This form is the same as \fBc\fR except that it stores one or more
16-bit integers in little-endian byte order in the output string.  The
low-order 16-bits of each integer are stored as a two-byte value at
the cursor position with the least significant byte stored first.  For
example,
.RS 
.PP
.CS
\fBbinary format\fR s3 {3 -3 258 1}
.CE 
.PP
will return a binary string equivalent to:
.PP
.CS
\fB\ex03\ex00\exfd\exff\ex02\ex01\fR
.CE
.RE
.IP \fBS\fR 5
This form is the same as \fBs\fR except that it stores one or more
16-bit integers in big-endian byte order in the output string.  For
example,
.RS 
.PP
.CS
\fBbinary format\fR S3 {3 -3 258 1}
.CE 
.PP
will return a binary string equivalent to:
.PP
.CS
\fB\ex00\ex03\exff\exfd\ex01\ex02\fR
.CE
.RE
.IP \fBt\fR 5
This form (mnemonically \fItiny\fR) is the same as \fBs\fR and \fBS\fR
except that it stores the 16-bit integers in the output string in the
native byte order of the machine where the Tcl script is running.
To determine what the native byte order of the machine is, refer to
the \fBbyteOrder\fR element of the \fBtcl_platform\fR array.
.IP \fBi\fR 5
This form is the same as \fBc\fR except that it stores one or more
32-bit integers in little-endian byte order in the output string.  The
low-order 32-bits of each integer are stored as a four-byte value at
the cursor position with the least significant byte stored first.  For
example,
.RS 
.PP
.CS
\fBbinary format\fR i3 {3 -3 65536 1}
.CE 
.PP
will return a binary string equivalent to:
.PP
.CS
\fB\ex03\ex00\ex00\ex00\exfd\exff\exff\exff\ex00\ex00\ex01\ex00\fR
.CE
.RE
.IP \fBI\fR 5
This form is the same as \fBi\fR except that it stores one or more one
or more 32-bit integers in big-endian byte order in the output string.
For example,
.RS 
.PP
.CS
\fBbinary format\fR I3 {3 -3 65536 1}
.CE 
.PP
will return a binary string equivalent to:
.PP
.CS
\fB\ex00\ex00\ex00\ex03\exff\exff\exff\exfd\ex00\ex01\ex00\ex00\fR
.CE
.RE
.IP \fBn\fR 5
This form (mnemonically \fInumber\fR or \fInormal\fR) is the same as
\fBi\fR and \fBI\fR except that it stores the 32-bit integers in the
output string in the native byte order of the machine where the Tcl
script is running.
To determine what the native byte order of the machine is, refer to
................................................................................
the \fBbyteOrder\fR element of the \fBtcl_platform\fR array.
.IP \fBw\fR 5
This form is the same as \fBc\fR except that it stores one or more
64-bit integers in little-endian byte order in the output string.  The
low-order 64-bits of each integer are stored as an eight-byte value at
the cursor position with the least significant byte stored first.  For
example,
.RS 
.PP
.CS
\fBbinary format\fR w 7810179016327718216
.CE 
.PP
will return the binary string \fBHelloTcl\fR.
.RE
.IP \fBW\fR 5
This form is the same as \fBw\fR except that it stores one or more one
or more 64-bit integers in big-endian byte order in the output string.
For example,
.RS 
.PP
.CS
\fBbinary format\fR Wc 4785469626960341345 110
.CE 
.PP
will return the binary string \fBBigEndian\fR
.RE
.IP \fBm\fR 5
This form (mnemonically the mirror of \fBw\fR) is the same as \fBw\fR
and \fBW\fR except that it stores the 64-bit integers in the output
string in the native byte order of the machine where the Tcl script is
running.
To determine what the native byte order of the machine is, refer to
................................................................................
point number may vary across architectures, so the number of bytes
that are generated may vary.  If the value overflows the
machine's native representation, then the value of FLT_MAX
as defined by the system will be used instead.  Because Tcl uses
double-precision floating point numbers internally, there may be some
loss of precision in the conversion to single-precision.  For example,
on a Windows system running on an Intel Pentium processor,
.RS 
.PP
.CS
\fBbinary format\fR f2 {1.6 3.4}
.CE 
.PP
will return a binary string equivalent to:
.PP
.CS
\fB\excd\excc\excc\ex3f\ex9a\ex99\ex59\ex40\fR
.CE
.RE
.IP \fBr\fR 5
This form (mnemonically \fIreal\fR) is the same as \fBf\fR except that
it stores the single-precision floating point numbers in little-endian
order.  This conversion only produces meaningful output when used on
machines which use the IEEE floating point representation (very
common, but not universal.)
................................................................................
This form is the same as \fBr\fR except that it stores the
single-precision floating point numbers in big-endian order.
.IP \fBd\fR 5
This form is the same as \fBf\fR except that it stores one or more one
or more double-precision floating point numbers in the machine's native
representation in the output string.  For example, on a
Windows system running on an Intel Pentium processor,
.RS 
.PP
.CS
\fBbinary format\fR d1 {1.6}
.CE 
.PP
will return a binary string equivalent to:
.PP
.CS
\fB\ex9a\ex99\ex99\ex99\ex99\ex99\exf9\ex3f\fR
.CE
.RE
.IP \fBq\fR 5
This form (mnemonically the mirror of \fBd\fR) is the same as \fBd\fR
except that it stores the double-precision floating point numbers in
little-endian order.  This conversion only produces meaningful output
when used on machines which use the IEEE floating point representation
(very common, but not universal.)
.IP \fBQ\fR 5
This form is the same as \fBq\fR except that it stores the
double-precision floating point numbers in big-endian order.
.IP \fBx\fR 5
Stores \fIcount\fR null bytes in the output string.  If \fIcount\fR is
not specified, stores one null byte.  If \fIcount\fR is
.QW \fB*\fR ,
generates an error.  This type does not consume an argument.  For
example,
.RS 
.PP
.CS
\fBbinary format\fR a3xa3x2a3 abc def ghi
.CE 
.PP
will return a binary string equivalent to:
.PP
.CS
\fBabc\e000def\e000\e000ghi\fR
.CE
.RE
.IP \fBX\fR 5
Moves the cursor back \fIcount\fR bytes in the output string.  If
\fIcount\fR is
.QW \fB*\fR
or is larger than the current cursor position,
then the cursor is positioned at location 0 so that the next byte
stored will be the first byte in the result string.  If \fIcount\fR is
omitted then the cursor is moved back one byte.  This type does not
consume an argument.  For example,
.RS 
.PP
.CS
\fBbinary format\fR a3X*a3X2a3 abc def ghi
.CE 
.PP
will return \fBdghi\fR.
.RE
.IP \[email protected]\fR 5
Moves the cursor to the absolute location in the output string
specified by \fIcount\fR.  Position 0 refers to the first byte in the
output string.  If \fIcount\fR refers to a position beyond the last
byte stored so far, then null bytes will be placed in the uninitialized
locations and the cursor will be placed at the specified location.  If
\fIcount\fR is
.QW \fB*\fR ,
then the cursor is moved to the current end of
the output string.  If \fIcount\fR is omitted, then an error will be
generated.  This type does not consume an argument. For example,
.RS 
.PP
.CS
\fBbinary format\fR [email protected]@*[email protected] abcde f ghi j
.CE 
.PP
will return
.PP
.CS
\fBabfdeghi\e000\e000j\fR
.CE
.RE
.SH "BINARY SCAN"
.PP
The \fBbinary scan\fR command parses fields from a binary string,
returning the number of conversions performed.  \fIString\fR gives the
input bytes to be parsed (one byte per character, and characters not
representable as a byte have their high bits chopped)
................................................................................
spaces.  Each field specifier is a single type character followed by
an optional flag character followed by an optional numeric \fIcount\fR.
Most field specifiers consume one
argument to obtain the variable into which the scanned values should
be placed.  The type character specifies how the binary data is to be
interpreted.  The \fIcount\fR typically indicates how many items of
the specified type are taken from the data.  If present, the
\fIcount\fR is a non-negative decimal integer or
.QW \fB*\fR ,
which normally indicates that all of the remaining items in the data are to
be used.  If there are not enough bytes left after the current cursor
position to satisfy the current field specifier, then the
corresponding variable is left untouched and \fBbinary scan\fR returns
immediately with the number of variables that were set.  If there are
not enough arguments for all of the fields in the format string that
consume arguments, then an error is generated. The flag character
.QW u
may be given to cause some types to be read as unsigned values. The flag
is accepted for all field types but is ignored for non-integer fields.
.PP
A similar example as with \fBbinary format\fR should explain the
relation between field specifiers and arguments in case of the binary
scan subcommand: 
.PP
.CS
\fBbinary scan\fR $bytes s3s first second
.CE
.PP
This command (provided the binary string in the variable \fIbytes\fR
is long enough) assigns a list of three integers to the variable
\fIfirst\fR and assigns a single value to the variable \fIsecond\fR.
If \fIbytes\fR contains fewer than 8 bytes (i.e. four 2-byte
integers), no assignment to \fIsecond\fR will be made, and if
\fIbytes\fR contains fewer than 6 bytes (i.e. three 2-byte integers),
no assignment to \fIfirst\fR will be made.  Hence: 
.PP
.CS
puts [\fBbinary scan\fR abcdefg s3s first second]
puts $first
puts $second
.CE 
.PP
will print (assuming neither variable is set previously): 
.PP
.CS
1
25185 25699 26213
can't read "second": no such variable
.CE
.PP
It is \fIimportant\fR to note that the \fBc\fR, \fBs\fR, and \fBS\fR
(and \fBi\fR and \fBI\fR on 64bit systems) will be scanned into
long data size values.  In doing this, values that have their high
bit set (0x80 for chars, 0x8000 for shorts, 0x80000000 for ints),
will be sign extended.  Thus the following will occur: 
.PP
.CS
set signShort [\fBbinary format\fR s1 0x8000]
\fBbinary scan\fR $signShort s1 val; \fI# val == 0xFFFF8000\fR
.CE 
.PP
If you require unsigned values you can include the
.QW u
flag character following
the field type. For example, to read an unsigned short value: 
.PP
.CS
set signShort [\fBbinary format\fR s1 0x8000]
\fBbinary scan\fR $signShort su1 val; \fI# val == 0x00008000\fR
.CE
.PP
Each type-count pair moves an imaginary cursor through the binary data,
reading bytes from the current position.  The cursor is initially
at position 0 at the beginning of the data.  The type may be any one of
the following characters:
.IP \fBa\fR 5
The data is a byte string of length \fIcount\fR.  If \fIcount\fR is
.QW \fB*\fR ,
then all of the remaining bytes in \fIstring\fR will be
scanned into the variable.  If \fIcount\fR is omitted, then one
byte will be scanned.
All bytes scanned will be interpreted as being characters in the
range \eu0000-\eu00ff so the \fBencoding convertfrom\fR command will be
needed if the string is not a binary string or a string encoded in ISO
8859\-1.
For example,
.RS 
.PP
.CS
\fBbinary scan\fR abcde\e000fghi a6a10 var1 var2
.CE 
.PP
will return \fB1\fR with the string equivalent to \fBabcde\e000\fR
stored in \fIvar1\fR and \fIvar2\fR left unmodified, and 
.PP
.CS
\fBbinary scan\fR \e342\e202\e254 a* var1
set var2 [encoding convertfrom utf-8 $var1]
.CE 
.PP
will store a Euro-currency character in \fIvar2\fR.
.RE
.IP \fBA\fR 5
This form is the same as \fBa\fR, except trailing blanks and nulls are stripped from
the scanned value before it is stored in the variable.  For example,
.RS 
.PP
.CS
\fBbinary scan\fR "abc efghi  \e000" A* var1
.CE 
.PP
will return \fB1\fR with \fBabc efghi\fR stored in \fIvar1\fR.
.RE
.IP \fBb\fR 5
The data is turned into a string of \fIcount\fR binary digits in
low-to-high order represented as a sequence of
.QW 1
and
.QW 0
characters.  The data bytes are scanned in first to last order with
the bits being taken in low-to-high order within each byte.  Any extra
bits in the last byte are ignored.  If \fIcount\fR is
.QW \fB*\fR ,
then all of the remaining bits in \fIstring\fR will be scanned.  If
\fIcount\fR is omitted, then one bit will be scanned.  For example,
.RS 
.PP
.CS
\fBbinary scan\fR \ex07\ex87\ex05 b5b* var1 var2
.CE 
.PP
will return \fB2\fR with \fB11100\fR stored in \fIvar1\fR and
\fB1110000110100000\fR stored in \fIvar2\fR.
.RE
.IP \fBB\fR 5
This form is the same as \fBb\fR, except the bits are taken in
high-to-low order within each byte.  For example,
.RS 
.PP
.CS
\fBbinary scan\fR \ex70\ex87\ex05 B5B* var1 var2
.CE 
.PP
will return \fB2\fR with \fB01110\fR stored in \fIvar1\fR and
\fB1000011100000101\fR stored in \fIvar2\fR.
.RE
.IP \fBH\fR 5
The data is turned into a string of \fIcount\fR hexadecimal digits in
high-to-low order represented as a sequence of characters in the set
.QW 0123456789abcdef .
The data bytes are scanned in first to last
order with the hex digits being taken in high-to-low order within each
byte. Any extra bits in the last byte are ignored. If \fIcount\fR is
.QW \fB*\fR ,
then all of the remaining hex digits in \fIstring\fR will be
scanned. If \fIcount\fR is omitted, then one hex digit will be
scanned. For example,
.RS 
.PP
.CS
\fBbinary scan\fR \ex07\exC6\ex05\ex1f\ex34 H3H* var1 var2
.CE 
.PP
will return \fB2\fR with \fB07c\fR stored in \fIvar1\fR and
\fB051f34\fR stored in \fIvar2\fR.
.RE
.IP \fBh\fR 5
This form is the same as \fBH\fR, except the digits are taken in
reverse (low-to-high) order within each byte. For example,
.RS 
.PP
.CS
\fBbinary scan\fR \ex07\ex86\ex05\ex12\ex34 h3h* var1 var2
.CE 
.PP
will return \fB2\fR with \fB706\fR stored in \fIvar1\fR and
\fB502143\fR stored in \fIvar2\fR.
.PP
Note that most code that wishes to parse the hexadecimal digits from
multiple bytes in order should use the \fBH\fR format.
.RE
.IP \fBc\fR 5
The data is turned into \fIcount\fR 8-bit signed integers and stored
in the corresponding variable as a list, or as unsigned if \fBu\fR is placed
immediately after the \fBc\fR. If \fIcount\fR is
.QW \fB*\fR ,
then all of the remaining bytes in \fIstring\fR will be scanned.  If
\fIcount\fR is omitted, then one 8-bit integer will be scanned.  For
example,
.RS 
.PP
.CS
\fBbinary scan\fR \ex07\ex86\ex05 c2c* var1 var2
.CE 
.PP
will return \fB2\fR with \fB7 -122\fR stored in \fIvar1\fR and \fB5\fR
stored in \fIvar2\fR.  Note that the integers returned are signed unless





\fBcu\fR in place of \fBc\fR.
.RE
.IP \fBs\fR 5
The data is interpreted as \fIcount\fR 16-bit signed integers
represented in little-endian byte order, or as unsigned if \fBu\fR is placed
immediately after the \fBs\fR.  The integers are stored in
the corresponding variable as a list.  If \fIcount\fR is
.QW \fB*\fR ,
then all of the remaining bytes in \fIstring\fR will be scanned.  If
\fIcount\fR is omitted, then one 16-bit integer will be scanned.  For
example,
.RS 
.PP
.CS
\fBbinary scan\fR \ex05\ex00\ex07\ex00\exf0\exff s2s* var1 var2
.CE 
.PP
will return \fB2\fR with \fB5 7\fR stored in \fIvar1\fR and \fB\-16\fR
stored in \fIvar2\fR.  Note that the integers returned are signed unless





\fBsu\fR is used in place of \fBs\fR.
.RE
.IP \fBS\fR 5
This form is the same as \fBs\fR except that the data is interpreted
as \fIcount\fR 16-bit integers represented in big-endian byte
order.  For example,
.RS 
.PP
.CS
\fBbinary scan\fR \ex00\ex05\ex00\ex07\exff\exf0 S2S* var1 var2
.CE 
.PP
will return \fB2\fR with \fB5 7\fR stored in \fIvar1\fR and \fB\-16\fR
stored in \fIvar2\fR.
.RE
.IP \fBt\fR 5
The data is interpreted as \fIcount\fR 16-bit signed integers
represented in the native byte order of the machine running the Tcl
script, or as unsigned if \fBu\fR is placed
immediately after the \fBt\fR.  It is otherwise identical to \fBs\fR and \fBS\fR.
To determine what the native byte order of the machine is, refer to
the \fBbyteOrder\fR element of the \fBtcl_platform\fR array.
.IP \fBi\fR 5
The data is interpreted as \fIcount\fR 32-bit signed integers
represented in little-endian byte order, or as unsigned if \fBu\fR is placed
immediately after the \fBi\fR.  The integers are stored in
the corresponding variable as a list.  If \fIcount\fR is
.QW \fB*\fR ,
then all of the remaining bytes in \fIstring\fR will be scanned.  If
\fIcount\fR is omitted, then one 32-bit integer will be scanned.  For
example,
.RS 
.PP
.CS
set str \ex05\ex00\ex00\ex00\ex07\ex00\ex00\ex00\exf0\exff\exff\exff
\fBbinary scan\fR $str i2i* var1 var2
.CE 
.PP
will return \fB2\fR with \fB5 7\fR stored in \fIvar1\fR and \fB\-16\fR
stored in \fIvar2\fR.  Note that the integers returned are signed unless

\fBiu\fR is used in place of \fBi\fR.



.RE
.IP \fBI\fR 5
This form is the same as \fBI\fR except that the data is interpreted
as \fIcount\fR 32-bit signed integers represented in big-endian byte
order, or as unsigned if \fBu\fR is placed
immediately after the \fBI\fR.  For example,
.RS 
.PP
.CS
set str \ex00\ex00\ex00\ex05\ex00\ex00\ex00\ex07\exff\exff\exff\exf0
\fBbinary scan\fR $str I2I* var1 var2
.CE 
.PP
will return \fB2\fR with \fB5 7\fR stored in \fIvar1\fR and \fB\-16\fR
stored in \fIvar2\fR.
.RE
.IP \fBn\fR 5
The data is interpreted as \fIcount\fR 32-bit signed integers
represented in the native byte order of the machine running the Tcl
script, or as unsigned if \fBu\fR is placed
immediately after the \fBn\fR.  It is otherwise identical to \fBi\fR and \fBI\fR.
To determine what the native byte order of the machine is, refer to
the \fBbyteOrder\fR element of the \fBtcl_platform\fR array.
.IP \fBw\fR 5
The data is interpreted as \fIcount\fR 64-bit signed integers
represented in little-endian byte order, or as unsigned if \fBu\fR is placed
immediately after the \fBw\fR.  The integers are stored in
the corresponding variable as a list.  If \fIcount\fR is
.QW \fB*\fR ,
then all of the remaining bytes in \fIstring\fR will be scanned.  If
\fIcount\fR is omitted, then one 64-bit integer will be scanned.  For
example,
.RS 
.PP
.CS
set str \ex05\ex00\ex00\ex00\ex07\ex00\ex00\ex00\exf0\exff\exff\exff
\fBbinary scan\fR $str wi* var1 var2
.CE 
.PP
will return \fB2\fR with \fB30064771077\fR stored in \fIvar1\fR and
\fB\-16\fR stored in \fIvar2\fR.

.RE
.IP \fBW\fR 5
This form is the same as \fBw\fR except that the data is interpreted
as \fIcount\fR 64-bit signed integers represented in big-endian byte
order, or as unsigned if \fBu\fR is placed
immediately after the \fBW\fR.  For example,
.RS 
.PP
.CS
set str \ex00\ex00\ex00\ex05\ex00\ex00\ex00\ex07\exff\exff\exff\exf0
\fBbinary scan\fR $str WI* var1 var2
.CE 
.PP
will return \fB2\fR with \fB21474836487\fR stored in \fIvar1\fR and \fB\-16\fR
stored in \fIvar2\fR.
.RE
.IP \fBm\fR 5
The data is interpreted as \fIcount\fR 64-bit signed integers
represented in the native byte order of the machine running the Tcl
script, or as unsigned if \fBu\fR is placed
immediately after the \fBm\fR.  It is otherwise identical to \fBw\fR and \fBW\fR.
To determine what the native byte order of the machine is, refer to
the \fBbyteOrder\fR element of the \fBtcl_platform\fR array.
.IP \fBf\fR 5
The data is interpreted as \fIcount\fR single-precision floating point
numbers in the machine's native representation.  The floating point
numbers are stored in the corresponding variable as a list.  If
\fIcount\fR is
.QW \fB*\fR ,
then all of the remaining bytes in
\fIstring\fR will be scanned.  If \fIcount\fR is omitted, then one
single-precision floating point number will be scanned.  The size of a
floating point number may vary across architectures, so the number of
bytes that are scanned may vary.  If the data does not represent a
valid floating point number, the resulting value is undefined and
compiler dependent.  For example, on a Windows system running on an
Intel Pentium processor,
.RS 
.PP
.CS
\fBbinary scan\fR \ex3f\excc\excc\excd f var1
.CE 
.PP
will return \fB1\fR with \fB1.6000000238418579\fR stored in
\fIvar1\fR.
.RE
.IP \fBr\fR 5
This form is the same as \fBf\fR except that the data is interpreted
as \fIcount\fR single-precision floating point number in little-endian
order.  This conversion is not portable to the minority of systems not
................................................................................
order.  This conversion is not portable to the minority of systems not
using IEEE floating point representations.
.IP \fBd\fR 5
This form is the same as \fBf\fR except that the data is interpreted
as \fIcount\fR double-precision floating point numbers in the
machine's native representation. For example, on a Windows system
running on an Intel Pentium processor,
.RS 
.PP
.CS
\fBbinary scan\fR \ex9a\ex99\ex99\ex99\ex99\ex99\exf9\ex3f d var1
.CE 
.PP
will return \fB1\fR with \fB1.6000000000000001\fR
stored in \fIvar1\fR.
.RE
.IP \fBq\fR 5
This form is the same as \fBd\fR except that the data is interpreted
as \fIcount\fR double-precision floating point number in little-endian
order.  This conversion is not portable to the minority of systems not
................................................................................
.IP \fBQ\fR 5
This form is the same as \fBd\fR except that the data is interpreted
as \fIcount\fR double-precision floating point number in big-endian
order.  This conversion is not portable to the minority of systems not
using IEEE floating point representations.
.IP \fBx\fR 5
Moves the cursor forward \fIcount\fR bytes in \fIstring\fR.  If
\fIcount\fR is
.QW \fB*\fR
or is larger than the number of bytes after the
current cursor position, then the cursor is positioned after
the last byte in \fIstring\fR.  If \fIcount\fR is omitted, then the
cursor is moved forward one byte.  Note that this type does not
consume an argument.  For example,
.RS 
.PP
.CS
\fBbinary scan\fR \ex01\ex02\ex03\ex04 x2H* var1
.CE 
.PP
will return \fB1\fR with \fB0304\fR stored in \fIvar1\fR.
.RE
.IP \fBX\fR 5
Moves the cursor back \fIcount\fR bytes in \fIstring\fR.  If
\fIcount\fR is
.QW \fB*\fR
or is larger than the current cursor position,
then the cursor is positioned at location 0 so that the next byte
scanned will be the first byte in \fIstring\fR.  If \fIcount\fR
is omitted then the cursor is moved back one byte.  Note that this
type does not consume an argument.  For example,
.RS 
.PP
.CS
\fBbinary scan\fR \ex01\ex02\ex03\ex04 c2XH* var1 var2
.CE 
.PP
will return \fB2\fR with \fB1 2\fR stored in \fIvar1\fR and \fB020304\fR
stored in \fIvar2\fR.
.RE
.IP \[email protected]\fR 5
Moves the cursor to the absolute location in the data string specified
by \fIcount\fR.  Note that position 0 refers to the first byte in
\fIstring\fR.  If \fIcount\fR refers to a position beyond the end of
\fIstring\fR, then the cursor is positioned after the last byte.  If
\fIcount\fR is omitted, then an error will be generated.  For example,
.RS 
.PP
.CS
\fBbinary scan\fR \ex01\ex02\ex03\ex04 [email protected]* var1 var2
.CE 
.PP
will return \fB2\fR with \fB1 2\fR stored in \fIvar1\fR and \fB020304\fR
stored in \fIvar2\fR.
.RE
.SH "PORTABILITY ISSUES"
.PP
The \fBr\fR, \fBR\fR, \fBq\fR and \fBQ\fR conversions will only work
reliably for transferring data between computers which are all using

Changes to doc/expr.n.

153
154
155
156
157
158
159







160




161
162
163
164
165
166
167
...
396
397
398
399
400
401
402








403
404
405
406
407
408
409
...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
\fB<<\0\0>>\fR
.
Left and right shift.  Valid for integers.
A right shift always propagates the sign bit.
.TP 20
\fB<\0\0>\0\0<=\0\0>=\fR
.







Boolean less than, greater than, less than or equal, and greater than or equal.




.TP 20
\fB==\0\0!=\fR
.
Boolean equal and not equal.
.TP 20
\fBeq\0\0ne\fR
.
................................................................................
.CE
.PP
A string comparison whose result is 1:
.PP
.CS
\fBexpr\fR {"0y" > "0x12"}
.CE








.PP
Define a procedure that computes an
.QW interesting
mathematical function:
.PP
.CS
proc tcl::mathfunc::calc {x y} {
................................................................................
.SH "SEE ALSO"
array(n), for(n), if(n), mathfunc(n), mathop(n), namespace(n), proc(n),
string(n), Tcl(n), while(n)
.SH KEYWORDS
arithmetic, boolean, compare, expression, fuzzy comparison
.SH COPYRIGHT
.nf
Copyright (c) 1993 The Regents of the University of California.
Copyright (c) 1994-2000 Sun Microsystems Incorporated.
Copyright (c) 2005 by Kevin B. Kenny <[email protected]>. All rights reserved.
.fi
'\" Local Variables:
'\" mode: nroff
'\" End:






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







 







>
>
>
>
>
>
>
>







 







|
|
|




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
...
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
...
471
472
473
474
475
476
477
478
479
480
481
482
483
484
\fB<<\0\0>>\fR
.
Left and right shift.  Valid for integers.
A right shift always propagates the sign bit.
.TP 20
\fB<\0\0>\0\0<=\0\0>=\fR
.
Boolean numeric-preferring comparisons: less than, greater than, less than or
equal, and greater than or equal. If either argument is not numeric, the
comparison is done using UNICODE string comparison, as with the string
comparison operators below, which have the same precedence.
.TP 20
\fBlt\0\0gt\0\0le\0\0ge\fR
.VS "8.7, TIP461"
Boolean string comparisons: less than, greater than, less than or equal, and
greater than or equal. These always compare values using their UNICODE strings
(also see \fBstring compare\fR), unlike with the numeric-preferring
comparisons abov, which have the same precedence.
.VE "8.7, TIP461"
.TP 20
\fB==\0\0!=\fR
.
Boolean equal and not equal.
.TP 20
\fBeq\0\0ne\fR
.
................................................................................
.CE
.PP
A string comparison whose result is 1:
.PP
.CS
\fBexpr\fR {"0y" > "0x12"}
.CE
.PP
.VS "8.7, TIP461"
A forced string comparison whose result is 0:
.PP
.CS
\fBexpr\fR {"0x03" gt "2"}
.CE
.VE "8.7, TIP461"
.PP
Define a procedure that computes an
.QW interesting
mathematical function:
.PP
.CS
proc tcl::mathfunc::calc {x y} {
................................................................................
.SH "SEE ALSO"
array(n), for(n), if(n), mathfunc(n), mathop(n), namespace(n), proc(n),
string(n), Tcl(n), while(n)
.SH KEYWORDS
arithmetic, boolean, compare, expression, fuzzy comparison
.SH COPYRIGHT
.nf
Copyright \(co 1993 The Regents of the University of California.
Copyright \(co 1994-2000 Sun Microsystems Incorporated.
Copyright \(co 2005 by Kevin B. Kenny <[email protected]>. All rights reserved.
.fi
'\" Local Variables:
'\" mode: nroff
'\" End:

Added doc/fpclassify.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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
'\"
'\" Copyright (c) 2018 by Kevin B. Kenny <[email protected]>. All rights reserved
'\" Copyright (c) 2019 by Donal Fellows
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
.TH fpclassify n 8.7 Tcl "Tcl Float Classifier"
.so man.macros
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
fpclassify \- Floating point number classification of Tcl values
.SH SYNOPSIS
package require \fBTcl 8.7\fR
.sp
\fBfpclassify \fIvalue\fR
.BE
.SH DESCRIPTION
The \fBfpclassify\fR command takes a floating point number, \fIvalue\fR, and
returns one of the following strings that describe it:
.TP
\fBzero\fR
.
\fIvalue\fR is a floating point zero.
.TP
\fBsubnormal\fR
.
\fIvalue\fR is the result of a gradual underflow.
.TP
\fBnormal\fR
.
\fIvalue\fR is an ordinary floating-point number (not zero, subnormal,
infinite, nor NaN).
.TP
\fBinfinite\fR
.
\fIvalue\fR is a floating-point infinity.
.TP
\fBnan\fR
.
\fIvalue\fR is Not-a-Number.
.PP
The \fBfpclassify\fR command throws an error if value is not a floating-point
value and cannot be converted to one.
.SH EXAMPLE
.PP
This shows how to check whether the result of a computation is numerically
safe or not. (Note however that it does not guard against numerical errors;
just against representational problems.)
.PP
.CS
set value [command-that-computes-a-value]
switch [\fBfpclassify\fR $value] {
    normal - zero {
        puts "Result is $value"
    }
    infinite {
        puts "Result is infinite"
    }
    subnormal {
        puts "Result is $value - WARNING! precision lost"
    }
    nan {
        puts "Computation completely failed"
    }
}
.CE
.SH "SEE ALSO"
expr(n), mathfunc(n)
.SH KEYWORDS
floating point
.SH STANDARDS
This command depends on the \fBfpclassify\fR() C macro conforming to
.QW "ISO C99"
(i.e., to ISO/IEC 9899:1999).
.SH COPYRIGHT
.nf
Copyright \(co 2018 by Kevin B. Kenny <[email protected]>. All rights reserved
.fi
'\" Local Variables:
'\" mode: nroff
'\" End:

Changes to doc/mathfunc.n.

42
43
44
45
46
47
48
49










50






51
52
53
54
55
56
57
..
88
89
90
91
92
93
94
95
96
97
98
99


100
101
102
103
104
105
106
107
108
109
110
...
202
203
204
205
206
207
208




























209
210
211
212
213
214

















215
216
217
218
219
220
221
...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
\fB::tcl::mathfunc::floor\fR \fIarg\fR
.br
\fB::tcl::mathfunc::fmod\fR \fIx\fR \fIy\fR
.br
\fB::tcl::mathfunc::hypot\fR \fIx\fR \fIy\fR
.br
\fB::tcl::mathfunc::int\fR \fIarg\fR
.br










\fB::tcl::mathfunc::isqrt\fR \fIarg\fR






.br
\fB::tcl::mathfunc::log\fR \fIarg\fR
.br
\fB::tcl::mathfunc::log10\fR \fIarg\fR
.br
\fB::tcl::mathfunc::max\fR \fIarg\fR ?\fIarg\fR ...?
.br
................................................................................
namespace \fB::tcl::mathfunc\fR; these functions are also available
for code apart from \fBexpr\fR, by invoking the given commands
directly.
.PP
Tcl supports the following mathematical functions in expressions, all
of which work solely with floating-point numbers unless otherwise noted:
.DS
.ta 3c 6c 9c
\fBabs\fR	\fBacos\fR	\fBasin\fR	\fBatan\fR
\fBatan2\fR	\fBbool\fR	\fBceil\fR	\fBcos\fR
\fBcosh\fR	\fBdouble\fR	\fBentier\fR	\fBexp\fR
\fBfloor\fR	\fBfmod\fR	\fBhypot\fR	\fBint\fR


\fBisqrt\fR	\fBlog\fR	\fBlog10\fR	\fBmax\fR
\fBmin\fR	\fBpow\fR	\fBrand\fR	\fBround\fR
\fBsin\fR	\fBsinh\fR	\fBsqrt\fR	\fBsrand\fR
\fBtan\fR	\fBtanh\fR	\fBwide\fR
.DE
.PP
In addition to these predefined functions, applications may
define additional functions by using \fBproc\fR (or any other method,
such as \fBinterp alias\fR or \fBTcl_CreateObjCommand\fR) to define
new commands in the \fBtcl::mathfunc\fR namespace.
.SS "DETAILED DEFINITIONS"
................................................................................
.
The argument may be any numeric value.  The integer part of \fIarg\fR
is determined, and then the low order bits of that integer value up
to the machine word size are returned as an integer value.  For reference,
the number of bytes in the machine word are stored in the \fBwordSize\fR
element of the \fBtcl_platform\fR array.
.TP




























\fBisqrt \fIarg\fR
.
Computes the integer part of the square root of \fIarg\fR.  \fIArg\fR must be
a positive value, either an integer or a floating point number.
Unlike \fBsqrt\fR, which is limited to the precision of a floating point
number, \fIisqrt\fR will return a result of arbitrary precision.

















.TP
\fBlog \fIarg\fR
.
Returns the natural logarithm of \fIarg\fR.  \fIArg\fR must be a
positive value.
.TP
\fBlog10 \fIarg\fR
................................................................................
.TP
\fBwide \fIarg\fR
.
The argument may be any numeric value.  The integer part of \fIarg\fR
is determined, and then the low order 64 bits of that integer value
are returned as an integer value.
.SH "SEE ALSO"
expr(n), mathop(n), namespace(n)
.SH "COPYRIGHT"
.nf
Copyright (c) 1993 The Regents of the University of California.
Copyright (c) 1994-2000 Sun Microsystems Incorporated.
Copyright (c) 2005, 2006 by Kevin B. Kenny <[email protected]>.
.fi
'\" Local Variables:
'\" mode: nroff
'\" fill-column: 78
'\" End:







>
>
>
>
>
>
>
>
>
>

>
>
>
>
>
>







 







|




>
>
|
|
|
|







 







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






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







 







|


|
|
|





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
...
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
...
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
...
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
\fB::tcl::mathfunc::floor\fR \fIarg\fR
.br
\fB::tcl::mathfunc::fmod\fR \fIx\fR \fIy\fR
.br
\fB::tcl::mathfunc::hypot\fR \fIx\fR \fIy\fR
.br
\fB::tcl::mathfunc::int\fR \fIarg\fR
.br
.VS "8.7, TIP 521"
\fB::tcl::mathfunc::isfinite\fR \fIarg\fR
.br
\fB::tcl::mathfunc::isinf\fR \fIarg\fR
.br
\fB::tcl::mathfunc::isnan\fR \fIarg\fR
.br
\fB::tcl::mathfunc::isnormal\fR \fIarg\fR
.VE "8.7, TIP 521"
.br
\fB::tcl::mathfunc::isqrt\fR \fIarg\fR
.br
.VS "8.7, TIP 521"
\fB::tcl::mathfunc::issubnormal\fR \fIarg\fR
.br
\fB::tcl::mathfunc::isunordered\fR \fIx y\fR
.VE "8.7, TIP 521"
.br
\fB::tcl::mathfunc::log\fR \fIarg\fR
.br
\fB::tcl::mathfunc::log10\fR \fIarg\fR
.br
\fB::tcl::mathfunc::max\fR \fIarg\fR ?\fIarg\fR ...?
.br
................................................................................
namespace \fB::tcl::mathfunc\fR; these functions are also available
for code apart from \fBexpr\fR, by invoking the given commands
directly.
.PP
Tcl supports the following mathematical functions in expressions, all
of which work solely with floating-point numbers unless otherwise noted:
.DS
.ta 3.2c 6.4c 9.6c
\fBabs\fR	\fBacos\fR	\fBasin\fR	\fBatan\fR
\fBatan2\fR	\fBbool\fR	\fBceil\fR	\fBcos\fR
\fBcosh\fR	\fBdouble\fR	\fBentier\fR	\fBexp\fR
\fBfloor\fR	\fBfmod\fR	\fBhypot\fR	\fBint\fR
\fBisfinite\fR	\fBisinf\fR	\fBisnan\fR	\fBisnormal\fR
\fBisqrt\fR	\fBissubnormal\fR	\fBisunordered\fR	\fBlog\fR
\fBlog10\fR	\fBmax\fR	\fBmin\fR	\fBpow\fR
\fBrand\fR	\fBround\fR	\fBsin\fR	\fBsinh\fR
\fBsqrt\fR	\fBsrand\fR	\fBtan\fR	\fBtanh\fR
\fBwide\fR
.DE
.PP
In addition to these predefined functions, applications may
define additional functions by using \fBproc\fR (or any other method,
such as \fBinterp alias\fR or \fBTcl_CreateObjCommand\fR) to define
new commands in the \fBtcl::mathfunc\fR namespace.
.SS "DETAILED DEFINITIONS"
................................................................................
.
The argument may be any numeric value.  The integer part of \fIarg\fR
is determined, and then the low order bits of that integer value up
to the machine word size are returned as an integer value.  For reference,
the number of bytes in the machine word are stored in the \fBwordSize\fR
element of the \fBtcl_platform\fR array.
.TP
\fBisfinite \fIarg\fR
.VS "8.7, TIP 521"
Returns 1 if the floating-point number \fIarg\fR is finite. That is, if it is
zero, subnormal, or normal. Returns 0 if the number is infinite or NaN. Throws
an error if \fIarg\fR cannot be promoted to a floating-point value.
.VE "8.7, TIP 521"
.TP
\fBisinf \fIarg\fR
.VS "8.7, TIP 521"
Returns 1 if the floating-point number \fIarg\fR is infinite. Returns 0 if the
number is finite or NaN. Throws an error if \fIarg\fR cannot be promoted to a
floating-point value.
.VE "8.7, TIP 521"
.TP
\fBisnan \fIarg\fR
.VS "8.7, TIP 521"
Returns 1 if the floating-point number \fIarg\fR is Not-a-Number. Returns 0 if
the number is finite or infinite. Throws an error if \fIarg\fR cannot be
promoted to a floating-point value.
.VE "8.7, TIP 521"
.TP
\fBisnormal \fIarg\fR
.VS "8.7, TIP 521"
Returns 1 if the floating-point number \fIarg\fR is normal. Returns 0 if the
number is zero, subnormal, infinite or NaN. Throws an error if \fIarg\fR
cannot be promoted to a floating-point value.
.VE "8.7, TIP 521"
.TP
\fBisqrt \fIarg\fR
.
Computes the integer part of the square root of \fIarg\fR.  \fIArg\fR must be
a positive value, either an integer or a floating point number.
Unlike \fBsqrt\fR, which is limited to the precision of a floating point
number, \fIisqrt\fR will return a result of arbitrary precision.
.TP
\fBissubnormal \fIarg\fR
.VS "8.7, TIP 521"
Returns 1 if the floating-point number \fIarg\fR is subnormal, i.e., the
result of gradual underflow. Returns 0 if the number is zero, normal, infinite
or NaN. Throws an error if \fIarg\fR cannot be promoted to a floating-point
value.
.VE "8.7, TIP 521"
.TP
\fBisunordered \fIx y\fR
.VS "8.7, TIP 521"
Returns 1 if \fIx\fR and \fIy\fR cannot be compared for ordering, that is, if
either one is NaN. Returns 0 if both values can be ordered, that is, if they
are both chosen from among the set of zero, subnormal, normal and infinite
values. Throws an error if either \fIx\fR or \fIy\fR cannot be promoted to a
floating-point value.
.VE "8.7, TIP 521"
.TP
\fBlog \fIarg\fR
.
Returns the natural logarithm of \fIarg\fR.  \fIArg\fR must be a
positive value.
.TP
\fBlog10 \fIarg\fR
................................................................................
.TP
\fBwide \fIarg\fR
.
The argument may be any numeric value.  The integer part of \fIarg\fR
is determined, and then the low order 64 bits of that integer value
are returned as an integer value.
.SH "SEE ALSO"
expr(n), fpclassify(n), mathop(n), namespace(n)
.SH "COPYRIGHT"
.nf
Copyright \(co 1993 The Regents of the University of California.
Copyright \(co 1994-2000 Sun Microsystems Incorporated.
Copyright \(co 2005, 2006 by Kevin B. Kenny <[email protected]>.
.fi
'\" Local Variables:
'\" mode: nroff
'\" fill-column: 78
'\" End:

Changes to doc/mathop.n.

50
51
52
53
54
55
56










57
58
59
60
61
62
63
..
72
73
74
75
76
77
78
79

80
81
82
83
84
85
86
...
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
...
295
296
297
298
299
300
301
302
303




304
305
306
307
308
309
310
311
\fB::tcl::mathop::>=\fR ?\fIarg\fR ...?
.br
\fB::tcl::mathop::>\fR ?\fIarg\fR ...?
.br
\fB::tcl::mathop::eq\fR ?\fIarg\fR ...?
.br
\fB::tcl::mathop::ne\fR \fIarg arg\fR










.br
\fB::tcl::mathop::in\fR \fIarg list\fR
.br
\fB::tcl::mathop::ni\fR \fIarg list\fR
.sp
.BE
.SH DESCRIPTION
................................................................................
The following operator commands are supported:
.DS
.ta 2c 4c 6c 8c
\fB~\fR	\fB!\fR	\fB+\fR	\fB\-\fR	\fB*\fR
\fB/\fR	\fB%\fR	\fB**\fR	\fB&\fR	\fB|\fR
\fB^\fR	\fB>>\fR	\fB<<\fR	\fB==\fR	\fBeq\fR
\fB!=\fR	\fBne\fR	\fB<\fR	\fB<=\fR	\fB>\fR
\fB>=\fR	\fBin\fR	\fBni\fR

.DE
.SS "MATHEMATICAL OPERATORS"
.PP
The behaviors of the mathematical operator commands are as follows:
.TP
\fB!\fR \fIboolean\fR
.
................................................................................
\fB<\fR ?\fIarg\fR ...?
.
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be strictly more than the one preceding it.
Comparisons are performed preferentially on the numeric values, and are
otherwise performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value. When the
arguments are numeric but should be compared as strings, the \fBstring
compare\fR command should be used instead.
.TP
\fB<=\fR ?\fIarg\fR ...?
.
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be equal to or more than the one preceding it.
Comparisons are performed preferentially on the numeric values, and are
otherwise performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value. When the
arguments are numeric but should be compared as strings, the \fBstring
compare\fR command should be used instead.
.TP
\fB>\fR ?\fIarg\fR ...?
.
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be strictly less than the one preceding it.
Comparisons are performed preferentially on the numeric values, and are
otherwise performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value. When the
arguments are numeric but should be compared as strings, the \fBstring
compare\fR command should be used instead.
.TP
\fB>=\fR ?\fIarg\fR ...?
.
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be equal to or less than the one preceding it.
Comparisons are performed preferentially on the numeric values, and are
otherwise performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value. When the
arguments are numeric but should be compared as strings, the \fBstring
compare\fR command should be used instead.
































.SS "BIT-WISE OPERATORS"
.PP
The behaviors of the bit-wise operator commands (all of which only operate on
integral arguments) are as follows:
.TP
\fB~\fR \fInumber\fR
.
................................................................................

\fI# Test for list membership\fR
set gotIt [\fBin\fR 3 $list]

\fI# Test to see if a value is within some defined range\fR
set inRange [\fB<=\fR 1 $x 5]

\fI# Test to see if a list is sorted\fR
set sorted [\fB<=\fR {*}$list]




.CE
.SH "SEE ALSO"
expr(n), mathfunc(n), namespace(n)
.SH KEYWORDS
command, expression, operator
'\" Local Variables:
'\" mode: nroff
'\" End:






>
>
>
>
>
>
>
>
>
>







 







|
>







 







|
|








|
|








|
|








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







 







|

>
>
>
>








50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
..
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
...
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
...
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
\fB::tcl::mathop::>=\fR ?\fIarg\fR ...?
.br
\fB::tcl::mathop::>\fR ?\fIarg\fR ...?
.br
\fB::tcl::mathop::eq\fR ?\fIarg\fR ...?
.br
\fB::tcl::mathop::ne\fR \fIarg arg\fR
.br
.VS "8.7, TIP461"
\fB::tcl::mathop::lt\fR ?\fIarg\fR ...?
.br
\fB::tcl::mathop::le\fR ?\fIarg\fR ...?
.br
\fB::tcl::mathop::gt\fR ?\fIarg\fR ...?
.br
\fB::tcl::mathop::ge\fR ?\fIarg\fR ...?
.VE "8.7, TIP461"
.br
\fB::tcl::mathop::in\fR \fIarg list\fR
.br
\fB::tcl::mathop::ni\fR \fIarg list\fR
.sp
.BE
.SH DESCRIPTION
................................................................................
The following operator commands are supported:
.DS
.ta 2c 4c 6c 8c
\fB~\fR	\fB!\fR	\fB+\fR	\fB\-\fR	\fB*\fR
\fB/\fR	\fB%\fR	\fB**\fR	\fB&\fR	\fB|\fR
\fB^\fR	\fB>>\fR	\fB<<\fR	\fB==\fR	\fBeq\fR
\fB!=\fR	\fBne\fR	\fB<\fR	\fB<=\fR	\fB>\fR
\fB>=\fR	\fBin\fR	\fBni\fR	\fBlt\fR	\fBle\fR
\fBgt\fR	\fBge\fR
.DE
.SS "MATHEMATICAL OPERATORS"
.PP
The behaviors of the mathematical operator commands are as follows:
.TP
\fB!\fR \fIboolean\fR
.
................................................................................
\fB<\fR ?\fIarg\fR ...?
.
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be strictly more than the one preceding it.
Comparisons are performed preferentially on the numeric values, and are
otherwise performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value. When the
arguments are numeric but should be compared as strings, the \fBlt\fR
operator or the \fBstring compare\fR command should be used instead.
.TP
\fB<=\fR ?\fIarg\fR ...?
.
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be equal to or more than the one preceding it.
Comparisons are performed preferentially on the numeric values, and are
otherwise performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value. When the
arguments are numeric but should be compared as strings,  the \fBle\fR
operator or the \fBstring compare\fR command should be used instead.
.TP
\fB>\fR ?\fIarg\fR ...?
.
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be strictly less than the one preceding it.
Comparisons are performed preferentially on the numeric values, and are
otherwise performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value. When the
arguments are numeric but should be compared as strings, the \fBgt\fR
operator or the \fBstring compare\fR command should be used instead.
.TP
\fB>=\fR ?\fIarg\fR ...?
.
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be equal to or less than the one preceding it.
Comparisons are performed preferentially on the numeric values, and are
otherwise performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value. When the
arguments are numeric but should be compared as strings, the \fBge\fR
operator or the \fBstring compare\fR command should be used instead.
.TP
\fBlt\fR ?\fIarg\fR ...?
.VS "8.7, TIP461"
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be strictly more than the one preceding it.
Comparisons are performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value.
.VE "8.7, TIP461"
.TP
\fBle\fR ?\fIarg\fR ...?
.VS "8.7, TIP461"
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be equal to or strictly more than the one preceding it.
Comparisons are performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value.
.VE "8.7, TIP461"
.TP
\fBgt\fR ?\fIarg\fR ...?
.VS "8.7, TIP461"
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be strictly less than the one preceding it.
Comparisons are performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value.
.VE "8.7, TIP461"
.TP
\fBge\fR ?\fIarg\fR ...?
.VS "8.7, TIP461"
Returns whether the arbitrarily-many arguments are ordered, with each argument
after the first having to be equal to or strictly less than the one preceding it.
Comparisons are performed using UNICODE string comparison. If fewer than two
arguments are present, this operation always returns a true value.
.VE "8.7, TIP461"
.SS "BIT-WISE OPERATORS"
.PP
The behaviors of the bit-wise operator commands (all of which only operate on
integral arguments) are as follows:
.TP
\fB~\fR \fInumber\fR
.
................................................................................

\fI# Test for list membership\fR
set gotIt [\fBin\fR 3 $list]

\fI# Test to see if a value is within some defined range\fR
set inRange [\fB<=\fR 1 $x 5]

\fI# Test to see if a list is numerically sorted\fR
set sorted [\fB<=\fR {*}$list]

\fI# Test to see if a list is lexically sorted\fR
set alphaList {a b c d e f}
set sorted [\fBle\fR {*}$alphaList]
.CE
.SH "SEE ALSO"
expr(n), mathfunc(n), namespace(n)
.SH KEYWORDS
command, expression, operator
'\" Local Variables:
'\" mode: nroff
'\" End:

Changes to generic/tclAssembly.c.

468
469
470
471
472
473
474


475

476

477
478
479
480
481
482
483
...
526
527
528
529
530
531
532
533

534
535
536
537
538
539
540
    {"strcaseLower",	ASSEM_1BYTE,	INST_STR_LOWER,		1,	1},
    {"strcaseTitle",	ASSEM_1BYTE,	INST_STR_TITLE,		1,	1},
    {"strcaseUpper",	ASSEM_1BYTE,	INST_STR_UPPER,		1,	1},
    {"strcmp",		ASSEM_1BYTE,	INST_STR_CMP,		2,	1},
    {"strcat",		ASSEM_CONCAT1,	INST_STR_CONCAT1,	INT_MIN,1},
    {"streq",		ASSEM_1BYTE,	INST_STR_EQ,		2,	1},
    {"strfind",		ASSEM_1BYTE,	INST_STR_FIND,		2,	1},


    {"strindex",	ASSEM_1BYTE,	INST_STR_INDEX,		2,	1},

    {"strlen",		ASSEM_1BYTE,	INST_STR_LEN,		1,	1},

    {"strmap",		ASSEM_1BYTE,	INST_STR_MAP,		3,	1},
    {"strmatch",	ASSEM_BOOL,	INST_STR_MATCH,		2,	1},
    {"strneq",		ASSEM_1BYTE,	INST_STR_NEQ,		2,	1},
    {"strrange",	ASSEM_1BYTE,	INST_STR_RANGE,		3,	1},
    {"strreplace",	ASSEM_1BYTE,	INST_STR_REPLACE,	4,	1},
    {"strrfind",	ASSEM_1BYTE,	INST_STR_FIND_LAST,	2,	1},
    {"strtrim",		ASSEM_1BYTE,	INST_STR_TRIM,		2,	1},
................................................................................
    INST_COROUTINE_NAME,					/* 149 */
    INST_NS_CURRENT,						/* 151 */
    INST_INFO_LEVEL_NUM,					/* 152 */
    INST_RESOLVE_COMMAND,					/* 154 */
    INST_STR_TRIM, INST_STR_TRIM_LEFT, INST_STR_TRIM_RIGHT,	/* 166-168 */
    INST_CONCAT_STK,						/* 169 */
    INST_STR_UPPER, INST_STR_LOWER, INST_STR_TITLE,		/* 170-172 */
    INST_NUM_TYPE						/* 180 */

};

/*
 * Helper macros.
 */

#if defined(TCL_DEBUG_ASSEMBLY) && defined(__GNUC__) && __GNUC__ > 2






>
>

>

>







 







|
>







468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
...
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
    {"strcaseLower",	ASSEM_1BYTE,	INST_STR_LOWER,		1,	1},
    {"strcaseTitle",	ASSEM_1BYTE,	INST_STR_TITLE,		1,	1},
    {"strcaseUpper",	ASSEM_1BYTE,	INST_STR_UPPER,		1,	1},
    {"strcmp",		ASSEM_1BYTE,	INST_STR_CMP,		2,	1},
    {"strcat",		ASSEM_CONCAT1,	INST_STR_CONCAT1,	INT_MIN,1},
    {"streq",		ASSEM_1BYTE,	INST_STR_EQ,		2,	1},
    {"strfind",		ASSEM_1BYTE,	INST_STR_FIND,		2,	1},
    {"strge",		ASSEM_1BYTE,	INST_STR_GE,		2,	1},
    {"strgt",		ASSEM_1BYTE,	INST_STR_GT,		2,	1},
    {"strindex",	ASSEM_1BYTE,	INST_STR_INDEX,		2,	1},
    {"strle",		ASSEM_1BYTE,	INST_STR_LE,		2,	1},
    {"strlen",		ASSEM_1BYTE,	INST_STR_LEN,		1,	1},
    {"strlt",		ASSEM_1BYTE,	INST_STR_LT,		2,	1},
    {"strmap",		ASSEM_1BYTE,	INST_STR_MAP,		3,	1},
    {"strmatch",	ASSEM_BOOL,	INST_STR_MATCH,		2,	1},
    {"strneq",		ASSEM_1BYTE,	INST_STR_NEQ,		2,	1},
    {"strrange",	ASSEM_1BYTE,	INST_STR_RANGE,		3,	1},
    {"strreplace",	ASSEM_1BYTE,	INST_STR_REPLACE,	4,	1},
    {"strrfind",	ASSEM_1BYTE,	INST_STR_FIND_LAST,	2,	1},
    {"strtrim",		ASSEM_1BYTE,	INST_STR_TRIM,		2,	1},
................................................................................
    INST_COROUTINE_NAME,					/* 149 */
    INST_NS_CURRENT,						/* 151 */
    INST_INFO_LEVEL_NUM,					/* 152 */
    INST_RESOLVE_COMMAND,					/* 154 */
    INST_STR_TRIM, INST_STR_TRIM_LEFT, INST_STR_TRIM_RIGHT,	/* 166-168 */
    INST_CONCAT_STK,						/* 169 */
    INST_STR_UPPER, INST_STR_LOWER, INST_STR_TITLE,		/* 170-172 */
    INST_NUM_TYPE,						/* 180 */
    INST_STR_LT, INST_STR_GT, INST_STR_LE, INST_STR_GE		/* 191-194 */
};

/*
 * Helper macros.
 */

#if defined(TCL_DEBUG_ASSEMBLY) && defined(__GNUC__) && __GNUC__ > 2

Changes to generic/tclBasic.c.

19
20
21
22
23
24
25



26
27
28
29
30
31
32
...
113
114
115
116
117
118
119






120
121
122
123
124
125
126
127

128
129
130
131
132
133
134
...
233
234
235
236
237
238
239

240
241
242
243
244
245
246
...
401
402
403
404
405
406
407




408


409
410
411
412
413
414
415
...
480
481
482
483
484
485
486








487
488
489
490
491
492
493
....
7467
7468
7469
7470
7471
7472
7473





















































































































































































































































































































7474
7475
7476
7477
7478
7479
7480
#include "tclInt.h"
#include "tclOOInt.h"
#include "tclCompile.h"
#include "tommath.h"
#include <math.h>
#include <assert.h>




#define INTERP_STACK_INITIAL_SIZE 2000
#define CORO_STACK_INITIAL_SIZE    200

/*
 * Determine whether we're using IEEE floating point
 */
................................................................................
static Tcl_ObjCmdProc	ExprBinaryFunc;
static Tcl_ObjCmdProc	ExprBoolFunc;
static Tcl_ObjCmdProc	ExprCeilFunc;
static Tcl_ObjCmdProc	ExprDoubleFunc;
static Tcl_ObjCmdProc	ExprFloorFunc;
static Tcl_ObjCmdProc	ExprIntFunc;
static Tcl_ObjCmdProc	ExprIsqrtFunc;






static Tcl_ObjCmdProc	ExprMaxFunc;
static Tcl_ObjCmdProc	ExprMinFunc;
static Tcl_ObjCmdProc	ExprRandFunc;
static Tcl_ObjCmdProc	ExprRoundFunc;
static Tcl_ObjCmdProc	ExprSqrtFunc;
static Tcl_ObjCmdProc	ExprSrandFunc;
static Tcl_ObjCmdProc	ExprUnaryFunc;
static Tcl_ObjCmdProc	ExprWideFunc;

static void		MathFuncWrongNumArgs(Tcl_Interp *interp, int expected,
			    int actual, Tcl_Obj *const *objv);
static Tcl_NRPostProc	NRCoroutineCallerCallback;
static Tcl_NRPostProc	NRCoroutineExitCallback;
static Tcl_NRPostProc	NRCommand;

static void		ProcessUnexpectedResult(Tcl_Interp *interp,
................................................................................
    {"coroutine",	NULL,			NULL,			TclNRCoroutineObjCmd,	CMD_IS_SAFE},
    {"error",		Tcl_ErrorObjCmd,	TclCompileErrorCmd,	NULL,	CMD_IS_SAFE},
    {"eval",		Tcl_EvalObjCmd,		NULL,			TclNREvalObjCmd,	CMD_IS_SAFE},
    {"expr",		Tcl_ExprObjCmd,		TclCompileExprCmd,	TclNRExprObjCmd,	CMD_IS_SAFE},
    {"for",		Tcl_ForObjCmd,		TclCompileForCmd,	TclNRForObjCmd,	CMD_IS_SAFE},
    {"foreach",		Tcl_ForeachObjCmd,	TclCompileForeachCmd,	TclNRForeachCmd,	CMD_IS_SAFE},
    {"format",		Tcl_FormatObjCmd,	TclCompileFormatCmd,	NULL,	CMD_IS_SAFE},

    {"global",		Tcl_GlobalObjCmd,	TclCompileGlobalCmd,	NULL,	CMD_IS_SAFE},
    {"if",		Tcl_IfObjCmd,		TclCompileIfCmd,	TclNRIfObjCmd,	CMD_IS_SAFE},
    {"incr",		Tcl_IncrObjCmd,		TclCompileIncrCmd,	NULL,	CMD_IS_SAFE},
    {"join",		Tcl_JoinObjCmd,		NULL,			NULL,	CMD_IS_SAFE},
    {"lappend",		Tcl_LappendObjCmd,	TclCompileLappendCmd,	NULL,	CMD_IS_SAFE},
    {"lassign",		Tcl_LassignObjCmd,	TclCompileLassignCmd,	NULL,	CMD_IS_SAFE},
    {"lindex",		Tcl_LindexObjCmd,	TclCompileLindexCmd,	NULL,	CMD_IS_SAFE},
................................................................................
    { "double",	ExprDoubleFunc,	NULL			},
    { "entier",	ExprIntFunc,	NULL			},
    { "exp",	ExprUnaryFunc,	(ClientData) exp	},
    { "floor",	ExprFloorFunc,	NULL			},
    { "fmod",	ExprBinaryFunc,	(ClientData) fmod	},
    { "hypot",	ExprBinaryFunc,	(ClientData) hypot	},
    { "int",	ExprIntFunc,	NULL			},




    { "isqrt",	ExprIsqrtFunc,	NULL			},


    { "log",	ExprUnaryFunc,	(ClientData) log	},
    { "log10",	ExprUnaryFunc,	(ClientData) log10	},
    { "max",	ExprMaxFunc,	NULL			},
    { "min",	ExprMinFunc,	NULL			},
    { "pow",	ExprBinaryFunc,	(ClientData) pow	},
    { "rand",	ExprRandFunc,	NULL			},
    { "round",	ExprRoundFunc,	NULL			},
................................................................................
    { ">",	TclSortingOpCmd,	TclCompileGreaterOpCmd,
		/* unused */ {0},	NULL},
    { ">=",	TclSortingOpCmd,	TclCompileGeqOpCmd,
		/* unused */ {0},	NULL},
    { "==",	TclSortingOpCmd,	TclCompileEqOpCmd,
		/* unused */ {0},	NULL},
    { "eq",	TclSortingOpCmd,	TclCompileStreqOpCmd,








		/* unused */ {0},	NULL},
    { NULL,	NULL,			NULL,
		{0},			NULL}
};
 
/*
 *----------------------------------------------------------------------
................................................................................
     * To avoid duplicating the random number generation code we simply clean
     * up our state and call the real random number function. That function
     * will always succeed.
     */

    return ExprRandFunc(clientData, interp, 1, objv);
}





















































































































































































































































































































 
/*
 *----------------------------------------------------------------------
 *
 * MathFuncWrongNumArgs --
 *
 *	Generate an error message when a math function presents the wrong






>
>
>







 







>
>
>
>
>
>








>







 







>







 







>
>
>
>

>
>







 







>
>
>
>
>
>
>
>







 







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







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
...
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
...
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
...
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
....
7492
7493
7494
7495
7496
7497
7498
7499
7500
7501
7502
7503
7504
7505
7506
7507
7508
7509
7510
7511
7512
7513
7514
7515
7516
7517
7518
7519
7520
7521
7522
7523
7524
7525
7526
7527
7528
7529
7530
7531
7532
7533
7534
7535
7536
7537
7538
7539
7540
7541
7542
7543
7544
7545
7546
7547
7548
7549
7550
7551
7552
7553
7554
7555
7556
7557
7558
7559
7560
7561
7562
7563
7564
7565
7566
7567
7568
7569
7570
7571
7572
7573
7574
7575
7576
7577
7578
7579
7580
7581
7582
7583
7584
7585
7586
7587
7588
7589
7590
7591
7592
7593
7594
7595
7596
7597
7598
7599
7600
7601
7602
7603
7604
7605
7606
7607
7608
7609
7610
7611
7612
7613
7614
7615
7616
7617
7618
7619
7620
7621
7622
7623
7624
7625
7626
7627
7628
7629
7630
7631
7632
7633
7634
7635
7636
7637
7638
7639
7640
7641
7642
7643
7644
7645
7646
7647
7648
7649
7650
7651
7652
7653
7654
7655
7656
7657
7658
7659
7660
7661
7662
7663
7664
7665
7666
7667
7668
7669
7670
7671
7672
7673
7674
7675
7676
7677
7678
7679
7680
7681
7682
7683
7684
7685
7686
7687
7688
7689
7690
7691
7692
7693
7694
7695
7696
7697
7698
7699
7700
7701
7702
7703
7704
7705
7706
7707
7708
7709
7710
7711
7712
7713
7714
7715
7716
7717
7718
7719
7720
7721
7722
7723
7724
7725
7726
7727
7728
7729
7730
7731
7732
7733
7734
7735
7736
7737
7738
7739
7740
7741
7742
7743
7744
7745
7746
7747
7748
7749
7750
7751
7752
7753
7754
7755
7756
7757
7758
7759
7760
7761
7762
7763
7764
7765
7766
7767
7768
7769
7770
7771
7772
7773
7774
7775
7776
7777
7778
7779
7780
7781
7782
7783
7784
7785
7786
7787
7788
7789
7790
7791
7792
7793
7794
7795
7796
7797
7798
7799
7800
7801
7802
7803
7804
7805
7806
7807
7808
7809
7810
7811
7812
7813
7814
#include "tclInt.h"
#include "tclOOInt.h"
#include "tclCompile.h"
#include "tommath.h"
#include <math.h>
#include <assert.h>
#ifndef fpclassify /* Older MSVC */
#include <float.h>
#endif /* !fpclassify */

#define INTERP_STACK_INITIAL_SIZE 2000
#define CORO_STACK_INITIAL_SIZE    200

/*
 * Determine whether we're using IEEE floating point
 */
................................................................................
static Tcl_ObjCmdProc	ExprBinaryFunc;
static Tcl_ObjCmdProc	ExprBoolFunc;
static Tcl_ObjCmdProc	ExprCeilFunc;
static Tcl_ObjCmdProc	ExprDoubleFunc;
static Tcl_ObjCmdProc	ExprFloorFunc;
static Tcl_ObjCmdProc	ExprIntFunc;
static Tcl_ObjCmdProc	ExprIsqrtFunc;
static Tcl_ObjCmdProc   ExprIsFiniteFunc;
static Tcl_ObjCmdProc   ExprIsInfinityFunc;
static Tcl_ObjCmdProc   ExprIsNaNFunc;
static Tcl_ObjCmdProc   ExprIsNormalFunc;
static Tcl_ObjCmdProc   ExprIsSubnormalFunc;
static Tcl_ObjCmdProc   ExprIsUnorderedFunc;
static Tcl_ObjCmdProc	ExprMaxFunc;
static Tcl_ObjCmdProc	ExprMinFunc;
static Tcl_ObjCmdProc	ExprRandFunc;
static Tcl_ObjCmdProc	ExprRoundFunc;
static Tcl_ObjCmdProc	ExprSqrtFunc;
static Tcl_ObjCmdProc	ExprSrandFunc;
static Tcl_ObjCmdProc	ExprUnaryFunc;
static Tcl_ObjCmdProc	ExprWideFunc;
static Tcl_ObjCmdProc   FloatClassifyObjCmd;
static void		MathFuncWrongNumArgs(Tcl_Interp *interp, int expected,
			    int actual, Tcl_Obj *const *objv);
static Tcl_NRPostProc	NRCoroutineCallerCallback;
static Tcl_NRPostProc	NRCoroutineExitCallback;
static Tcl_NRPostProc	NRCommand;

static void		ProcessUnexpectedResult(Tcl_Interp *interp,
................................................................................
    {"coroutine",	NULL,			NULL,			TclNRCoroutineObjCmd,	CMD_IS_SAFE},
    {"error",		Tcl_ErrorObjCmd,	TclCompileErrorCmd,	NULL,	CMD_IS_SAFE},
    {"eval",		Tcl_EvalObjCmd,		NULL,			TclNREvalObjCmd,	CMD_IS_SAFE},
    {"expr",		Tcl_ExprObjCmd,		TclCompileExprCmd,	TclNRExprObjCmd,	CMD_IS_SAFE},
    {"for",		Tcl_ForObjCmd,		TclCompileForCmd,	TclNRForObjCmd,	CMD_IS_SAFE},
    {"foreach",		Tcl_ForeachObjCmd,	TclCompileForeachCmd,	TclNRForeachCmd,	CMD_IS_SAFE},
    {"format",		Tcl_FormatObjCmd,	TclCompileFormatCmd,	NULL,	CMD_IS_SAFE},
    {"fpclassify",      FloatClassifyObjCmd,    NULL,                   NULL,   CMD_IS_SAFE},
    {"global",		Tcl_GlobalObjCmd,	TclCompileGlobalCmd,	NULL,	CMD_IS_SAFE},
    {"if",		Tcl_IfObjCmd,		TclCompileIfCmd,	TclNRIfObjCmd,	CMD_IS_SAFE},
    {"incr",		Tcl_IncrObjCmd,		TclCompileIncrCmd,	NULL,	CMD_IS_SAFE},
    {"join",		Tcl_JoinObjCmd,		NULL,			NULL,	CMD_IS_SAFE},
    {"lappend",		Tcl_LappendObjCmd,	TclCompileLappendCmd,	NULL,	CMD_IS_SAFE},
    {"lassign",		Tcl_LassignObjCmd,	TclCompileLassignCmd,	NULL,	CMD_IS_SAFE},
    {"lindex",		Tcl_LindexObjCmd,	TclCompileLindexCmd,	NULL,	CMD_IS_SAFE},
................................................................................
    { "double",	ExprDoubleFunc,	NULL			},
    { "entier",	ExprIntFunc,	NULL			},
    { "exp",	ExprUnaryFunc,	(ClientData) exp	},
    { "floor",	ExprFloorFunc,	NULL			},
    { "fmod",	ExprBinaryFunc,	(ClientData) fmod	},
    { "hypot",	ExprBinaryFunc,	(ClientData) hypot	},
    { "int",	ExprIntFunc,	NULL			},
    { "isfinite", ExprIsFiniteFunc, NULL        	},
    { "isinf",	ExprIsInfinityFunc, NULL        	},
    { "isnan",	ExprIsNaNFunc,	NULL            	},
    { "isnormal", ExprIsNormalFunc, NULL        	},
    { "isqrt",	ExprIsqrtFunc,	NULL			},
    { "issubnormal", ExprIsSubnormalFunc, NULL,         },
    { "isunordered", ExprIsUnorderedFunc, NULL,         },
    { "log",	ExprUnaryFunc,	(ClientData) log	},
    { "log10",	ExprUnaryFunc,	(ClientData) log10	},
    { "max",	ExprMaxFunc,	NULL			},
    { "min",	ExprMinFunc,	NULL			},
    { "pow",	ExprBinaryFunc,	(ClientData) pow	},
    { "rand",	ExprRandFunc,	NULL			},
    { "round",	ExprRoundFunc,	NULL			},
................................................................................
    { ">",	TclSortingOpCmd,	TclCompileGreaterOpCmd,
		/* unused */ {0},	NULL},
    { ">=",	TclSortingOpCmd,	TclCompileGeqOpCmd,
		/* unused */ {0},	NULL},
    { "==",	TclSortingOpCmd,	TclCompileEqOpCmd,
		/* unused */ {0},	NULL},
    { "eq",	TclSortingOpCmd,	TclCompileStreqOpCmd,
		/* unused */ {0},	NULL},
    { "lt",	TclSortingOpCmd,	TclCompileStrLtOpCmd,
		/* unused */ {0},	NULL},
    { "le",	TclSortingOpCmd,	TclCompileStrLeOpCmd,
		/* unused */ {0},	NULL},
    { "gt",	TclSortingOpCmd,	TclCompileStrGtOpCmd,
		/* unused */ {0},	NULL},
    { "ge",	TclSortingOpCmd,	TclCompileStrGeOpCmd,
		/* unused */ {0},	NULL},
    { NULL,	NULL,			NULL,
		{0},			NULL}
};
 
/*
 *----------------------------------------------------------------------
................................................................................
     * To avoid duplicating the random number generation code we simply clean
     * up our state and call the real random number function. That function
     * will always succeed.
     */

    return ExprRandFunc(clientData, interp, 1, objv);
}
 
/*
 *----------------------------------------------------------------------
 *
 * Double Classification Functions --
 *
 *	This page contains the functions that implement all of the built-in
 *	math functions for classifying IEEE doubles.
 *
 *      These have to be a little bit careful while Tcl_GetDoubleFromObj()
 *      rejects NaN values, which these functions *explicitly* accept.
 *
 * Results:
 *	Each function returns TCL_OK if it succeeds and pushes an Tcl object
 *	holding the result. If it fails it returns TCL_ERROR and leaves an
 *	error message in the interpreter's result.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

/*
 * Older MSVC is supported by Tcl, but doesn't have fpclassify(). Of course.
 * But it does have _fpclass() which does almost the same job.
 *
 * This makes it conform to the C99 standard API, and just delegates to the
 * standard macro on platforms that do it correctly.
 */

static inline int
ClassifyDouble(
    double d)
{
#ifdef fpclassify
    return fpclassify(d);
#else /* !fpclassify */
#define FP_ZERO 0
#define FP_NORMAL 1
#define FP_SUBNORMAL 2
#define FP_INFINITE 3
#define FP_NAN 4

    switch (_fpclass(d)) {
    case _FPCLASS_NZ:
    case _FPCLASS_PZ:
        return FP_ZERO;
    case _FPCLASS_NN:
    case _FPCLASS_PN:
        return FP_NORMAL;
    case _FPCLASS_ND:
    case _FPCLASS_PD:
        return FP_SUBNORMAL;
    case _FPCLASS_NINF:
    case _FPCLASS_PINF:
        return FP_INFINITE;
    default:
        Tcl_Panic("result of _fpclass() outside documented range!");
    case _FPCLASS_QNAN:
    case _FPCLASS_SNAN:
        return FP_NAN;
    }
#endif /* fpclassify */
}

static int
ExprIsFiniteFunc(
    ClientData ignored,
    Tcl_Interp *interp,		/* The interpreter in which to execute the
				 * function. */
    int objc,			/* Actual parameter count */
    Tcl_Obj *const *objv)	/* Actual parameter list */
{
    double d;
    ClientData ptr;
    int type, result = 0;

    if (objc != 2) {
	MathFuncWrongNumArgs(interp, 2, objc, objv);
	return TCL_ERROR;
    }

    if (TclGetNumberFromObj(interp, objv[1], &ptr, &type) != TCL_OK) {
        return TCL_ERROR;
    }
    if (type != TCL_NUMBER_NAN) {
        if (Tcl_GetDoubleFromObj(interp, objv[1], &d) != TCL_OK) {
            return TCL_ERROR;
        }
        type = ClassifyDouble(d);
        result = (type != FP_INFINITE && type != FP_NAN);
    }
    Tcl_SetObjResult(interp, Tcl_NewBooleanObj(result));
    return TCL_OK;
}

static int
ExprIsInfinityFunc(
    ClientData ignored,
    Tcl_Interp *interp,		/* The interpreter in which to execute the
				 * function. */
    int objc,			/* Actual parameter count */
    Tcl_Obj *const *objv)	/* Actual parameter list */
{
    double d;
    ClientData ptr;
    int type, result = 0;

    if (objc != 2) {
	MathFuncWrongNumArgs(interp, 2, objc, objv);
	return TCL_ERROR;
    }

    if (TclGetNumberFromObj(interp, objv[1], &ptr, &type) != TCL_OK) {
        return TCL_ERROR;
    }
    if (type != TCL_NUMBER_NAN) {
        if (Tcl_GetDoubleFromObj(interp, objv[1], &d) != TCL_OK) {
            return TCL_ERROR;
        }
        result = (ClassifyDouble(d) == FP_INFINITE);
    }
    Tcl_SetObjResult(interp, Tcl_NewBooleanObj(result));
    return TCL_OK;
}

static int
ExprIsNaNFunc(
    ClientData ignored,
    Tcl_Interp *interp,		/* The interpreter in which to execute the
				 * function. */
    int objc,			/* Actual parameter count */
    Tcl_Obj *const *objv)	/* Actual parameter list */
{
    double d;
    ClientData ptr;
    int type, result = 1;

    if (objc != 2) {
	MathFuncWrongNumArgs(interp, 2, objc, objv);
	return TCL_ERROR;
    }

    if (TclGetNumberFromObj(interp, objv[1], &ptr, &type) != TCL_OK) {
        return TCL_ERROR;
    }
    if (type != TCL_NUMBER_NAN) {
        if (Tcl_GetDoubleFromObj(interp, objv[1], &d) != TCL_OK) {
            return TCL_ERROR;
        }
        result = (ClassifyDouble(d) == FP_NAN);
    }
    Tcl_SetObjResult(interp, Tcl_NewBooleanObj(result));
    return TCL_OK;
}

static int
ExprIsNormalFunc(
    ClientData ignored,
    Tcl_Interp *interp,		/* The interpreter in which to execute the
				 * function. */
    int objc,			/* Actual parameter count */
    Tcl_Obj *const *objv)	/* Actual parameter list */
{
    double d;
    ClientData ptr;
    int type, result = 0;

    if (objc != 2) {
	MathFuncWrongNumArgs(interp, 2, objc, objv);
	return TCL_ERROR;
    }

    if (TclGetNumberFromObj(interp, objv[1], &ptr, &type) != TCL_OK) {
        return TCL_ERROR;
    }
    if (type != TCL_NUMBER_NAN) {
        if (Tcl_GetDoubleFromObj(interp, objv[1], &d) != TCL_OK) {
            return TCL_ERROR;
        }
        result = (ClassifyDouble(d) == FP_NORMAL);
    }
    Tcl_SetObjResult(interp, Tcl_NewBooleanObj(result));
    return TCL_OK;
}

static int
ExprIsSubnormalFunc(
    ClientData ignored,
    Tcl_Interp *interp,		/* The interpreter in which to execute the
				 * function. */
    int objc,			/* Actual parameter count */
    Tcl_Obj *const *objv)	/* Actual parameter list */
{
    double d;
    ClientData ptr;
    int type, result = 0;

    if (objc != 2) {
	MathFuncWrongNumArgs(interp, 2, objc, objv);
	return TCL_ERROR;
    }

    if (TclGetNumberFromObj(interp, objv[1], &ptr, &type) != TCL_OK) {
        return TCL_ERROR;
    }
    if (type != TCL_NUMBER_NAN) {
        if (Tcl_GetDoubleFromObj(interp, objv[1], &d) != TCL_OK) {
            return TCL_ERROR;
        }
        result = (ClassifyDouble(d) == FP_SUBNORMAL);
    }
    Tcl_SetObjResult(interp, Tcl_NewBooleanObj(result));
    return TCL_OK;
}

static int
ExprIsUnorderedFunc(
    ClientData ignored,
    Tcl_Interp *interp,		/* The interpreter in which to execute the
				 * function. */
    int objc,			/* Actual parameter count */
    Tcl_Obj *const *objv)	/* Actual parameter list */
{
    double d;
    ClientData ptr;
    int type, result = 0;

    if (objc != 3) {
	MathFuncWrongNumArgs(interp, 3, objc, objv);
	return TCL_ERROR;
    }

    if (TclGetNumberFromObj(interp, objv[1], &ptr, &type) != TCL_OK) {
        return TCL_ERROR;
    }
    if (type == TCL_NUMBER_NAN) {
        result = 1;
    } else {
        d = *((const double *) ptr);
        result = (ClassifyDouble(d) == FP_NAN);
    }

    if (TclGetNumberFromObj(interp, objv[2], &ptr, &type) != TCL_OK) {
        return TCL_ERROR;
    }
    if (type == TCL_NUMBER_NAN) {
        result |= 1;
    } else {
        d = *((const double *) ptr);
        result |= (ClassifyDouble(d) == FP_NAN);
    }

    Tcl_SetObjResult(interp, Tcl_NewBooleanObj(result));
    return TCL_OK;
}

static int
FloatClassifyObjCmd(
    ClientData ignored,
    Tcl_Interp *interp,		/* The interpreter in which to execute the
				 * function. */
    int objc,			/* Actual parameter count */
    Tcl_Obj *const *objv)	/* Actual parameter list */
{
    double d;
    Tcl_Obj *objPtr;
    ClientData ptr;
    int type;

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

    if (TclGetNumberFromObj(interp, objv[1], &ptr, &type) != TCL_OK) {
        return TCL_ERROR;
    }
    if (type == TCL_NUMBER_NAN) {
        goto gotNaN;
    } else if (Tcl_GetDoubleFromObj(interp, objv[1], &d) != TCL_OK) {
        return TCL_ERROR;
    }
    switch (ClassifyDouble(d)) {
    case FP_INFINITE:
        TclNewLiteralStringObj(objPtr, "infinite");
        break;
    case FP_NAN:
    gotNaN:
        TclNewLiteralStringObj(objPtr, "nan");
        break;
    case FP_NORMAL:
        TclNewLiteralStringObj(objPtr, "normal");
        break;
    case FP_SUBNORMAL:
        TclNewLiteralStringObj(objPtr, "subnormal");
        break;
    case FP_ZERO:
        TclNewLiteralStringObj(objPtr, "zero");
        break;
    default:
        Tcl_SetObjResult(interp, Tcl_ObjPrintf(
                "unable to classify number: %f", d));
        return TCL_ERROR;
    }
    Tcl_SetObjResult(interp, objPtr);
    return TCL_OK;
}
 
/*
 *----------------------------------------------------------------------
 *
 * MathFuncWrongNumArgs --
 *
 *	Generate an error message when a math function presents the wrong

Changes to generic/tclCompCmdsSZ.c.

4495
4496
4497
4498
4499
4500
4501












































4502
4503
4504
4505
4506
4507
4508
    Tcl_Parse *parsePtr,
    Command *cmdPtr,		/* Points to defintion of command being
				 * compiled. */
    CompileEnv *envPtr)
{
    return CompileComparisonOpCmd(interp, parsePtr, INST_STR_EQ, envPtr);
}












































 
int
TclCompileMinusOpCmd(
    Tcl_Interp *interp,
    Tcl_Parse *parsePtr,
    Command *cmdPtr,		/* Points to defintion of command being
				 * compiled. */






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







4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
    Tcl_Parse *parsePtr,
    Command *cmdPtr,		/* Points to defintion of command being
				 * compiled. */
    CompileEnv *envPtr)
{
    return CompileComparisonOpCmd(interp, parsePtr, INST_STR_EQ, envPtr);
}

int
TclCompileStrLtOpCmd(
    Tcl_Interp *interp,
    Tcl_Parse *parsePtr,
    Command *cmdPtr,		/* Points to defintion of command being
				 * compiled. */
    CompileEnv *envPtr)
{
    return CompileComparisonOpCmd(interp, parsePtr, INST_STR_LT, envPtr);
}

int
TclCompileStrLeOpCmd(
    Tcl_Interp *interp,
    Tcl_Parse *parsePtr,
    Command *cmdPtr,		/* Points to defintion of command being
				 * compiled. */
    CompileEnv *envPtr)
{
    return CompileComparisonOpCmd(interp, parsePtr, INST_STR_LE, envPtr);
}

int
TclCompileStrGtOpCmd(
    Tcl_Interp *interp,
    Tcl_Parse *parsePtr,
    Command *cmdPtr,		/* Points to defintion of command being
				 * compiled. */
    CompileEnv *envPtr)
{
    return CompileComparisonOpCmd(interp, parsePtr, INST_STR_GT, envPtr);
}

int
TclCompileStrGeOpCmd(
    Tcl_Interp *interp,
    Tcl_Parse *parsePtr,
    Command *cmdPtr,		/* Points to defintion of command being
				 * compiled. */
    CompileEnv *envPtr)
{
    return CompileComparisonOpCmd(interp, parsePtr, INST_STR_GE, envPtr);
}
 
int
TclCompileMinusOpCmd(
    Tcl_Interp *interp,
    Tcl_Parse *parsePtr,
    Command *cmdPtr,		/* Points to defintion of command being
				 * compiled. */

Changes to generic/tclCompExpr.c.

277
278
279
280
281
282
283




284
285
286
287
288
289
290
291
...
356
357
358
359
360
361
362




363
364
365
366
367
368
369
370
371
372
373
374
375
...
411
412
413
414
415
416
417




418
419
420
421
422
423
424
425
426
427
428
429
430
....
1996
1997
1998
1999
2000
2001
2002





























2003
2004
2005
2006
2007
2008
2009
....
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
				 * for us. In the end though, a close paren is
				 * not really a binary operator, and some
				 * special coding in ParseExpr() make sure we
				 * never put an actual CLOSE_PAREN node in the
				 * parse tree. The sub-expression between
				 * parens becomes the single argument of the
				 * matching OPEN_PAREN unary operator. */




#define END		(BINARY | 28)
				/* This lexeme represents the end of the
				 * string being parsed. Treating it as a
				 * binary operator follows the same logic as
				 * the CLOSE_PAREN lexeme and END pairs with
				 * START, in the same way that CLOSE_PAREN
				 * pairs with OPEN_PAREN. */

................................................................................
    PREC_OR,		/* OR */
    PREC_EQUAL,		/* STREQ */
    PREC_EQUAL,		/* STRNEQ */
    PREC_EXPON,		/* EXPON */
    PREC_EQUAL,		/* IN_LIST */
    PREC_EQUAL,		/* NOT_IN_LIST */
    PREC_CLOSE_PAREN,	/* CLOSE_PAREN */




    PREC_END,		/* END */
    /* Expansion room for more binary operators */
    0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,
    /* Unary operator lexemes */
    PREC_UNARY,		/* UNARY_PLUS */
    PREC_UNARY,		/* UNARY_MINUS */
    PREC_UNARY,		/* FUNCTION */
    PREC_START,		/* START */
    PREC_OPEN_PAREN,	/* OPEN_PAREN */
    PREC_UNARY,		/* NOT*/
................................................................................
    0,			/* OR */
    INST_STR_EQ,	/* STREQ */
    INST_STR_NEQ,	/* STRNEQ */
    INST_EXPON,		/* EXPON */
    INST_LIST_IN,	/* IN_LIST */
    INST_LIST_NOT_IN,	/* NOT_IN_LIST */
    0,			/* CLOSE_PAREN */




    0,			/* END */
    /* Expansion room for more binary operators */
    0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,
    /* Unary operator lexemes */
    INST_UPLUS,		/* UNARY_PLUS */
    INST_UMINUS,	/* UNARY_MINUS */
    0,			/* FUNCTION */
    0,			/* START */
    0,			/* OPEN_PAREN */
    INST_LNOT,		/* NOT*/
................................................................................
		*lexemePtr = STRNEQ;
		return 2;
	    case 'i':
		*lexemePtr = NOT_IN_LIST;
		return 2;
	    }
	}





























    }

    literal = Tcl_NewObj();
    if (TclParseNumber(NULL, literal, NULL, start, numBytes, &end,
	    TCL_PARSE_NO_WHITESPACE) == TCL_OK) {
	if (end < start + numBytes && !TclIsBareword(*end)) {

................................................................................
}
 
/*
 *----------------------------------------------------------------------
 *
 * TclSortingOpCmd --
 *	Implements the commands:
 *		<, <=, >, >=, ==, eq
 *	in the ::tcl::mathop namespace. These commands are defined for
 *	arbitrary number of arguments by computing the AND of the base
 *	operator applied to all neighbor argument pairs.
 *
 * Results:
 *	A standard Tcl return code and result left in interp.
 *






>
>
>
>
|







 







>
>
>
>


<


<







 







>
>
>
>


<


<







 







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







 







|







277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
...
360
361
362
363
364
365
366
367
368
369
370
371
372

373
374

375
376
377
378
379
380
381
...
417
418
419
420
421
422
423
424
425
426
427
428
429

430
431

432
433
434
435
436
437
438
....
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
....
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
				 * for us. In the end though, a close paren is
				 * not really a binary operator, and some
				 * special coding in ParseExpr() make sure we
				 * never put an actual CLOSE_PAREN node in the
				 * parse tree. The sub-expression between
				 * parens becomes the single argument of the
				 * matching OPEN_PAREN unary operator. */
#define STR_LT		(BINARY | 28)
#define STR_GT		(BINARY | 29)
#define STR_LEQ		(BINARY | 30)
#define STR_GEQ		(BINARY | 31)
#define END		(BINARY | 32)
				/* This lexeme represents the end of the
				 * string being parsed. Treating it as a
				 * binary operator follows the same logic as
				 * the CLOSE_PAREN lexeme and END pairs with
				 * START, in the same way that CLOSE_PAREN
				 * pairs with OPEN_PAREN. */

................................................................................
    PREC_OR,		/* OR */
    PREC_EQUAL,		/* STREQ */
    PREC_EQUAL,		/* STRNEQ */
    PREC_EXPON,		/* EXPON */
    PREC_EQUAL,		/* IN_LIST */
    PREC_EQUAL,		/* NOT_IN_LIST */
    PREC_CLOSE_PAREN,	/* CLOSE_PAREN */
    PREC_COMPARE,	/* STR_LT */
    PREC_COMPARE,	/* STR_GT */
    PREC_COMPARE,	/* STR_LEQ */
    PREC_COMPARE,	/* STR_GEQ */
    PREC_END,		/* END */
    /* Expansion room for more binary operators */

    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,

    /* Unary operator lexemes */
    PREC_UNARY,		/* UNARY_PLUS */
    PREC_UNARY,		/* UNARY_MINUS */
    PREC_UNARY,		/* FUNCTION */
    PREC_START,		/* START */
    PREC_OPEN_PAREN,	/* OPEN_PAREN */
    PREC_UNARY,		/* NOT*/
................................................................................
    0,			/* OR */
    INST_STR_EQ,	/* STREQ */
    INST_STR_NEQ,	/* STRNEQ */
    INST_EXPON,		/* EXPON */
    INST_LIST_IN,	/* IN_LIST */
    INST_LIST_NOT_IN,	/* NOT_IN_LIST */
    0,			/* CLOSE_PAREN */
    INST_STR_LT,	/* STR_LT */
    INST_STR_GT,	/* STR_GT */
    INST_STR_LE,	/* STR_LEQ */
    INST_STR_GE,	/* STR_GEQ */
    0,			/* END */
    /* Expansion room for more binary operators */

    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,

    /* Unary operator lexemes */
    INST_UPLUS,		/* UNARY_PLUS */
    INST_UMINUS,	/* UNARY_MINUS */
    0,			/* FUNCTION */
    0,			/* START */
    0,			/* OPEN_PAREN */
    INST_LNOT,		/* NOT*/
................................................................................
		*lexemePtr = STRNEQ;
		return 2;
	    case 'i':
		*lexemePtr = NOT_IN_LIST;
		return 2;
	    }
	}
	break;

    case 'l':
	if ((numBytes > 1)
		&& ((numBytes == 2) || start[2] & 0x80 || !isalpha(UCHAR(start[2])))) {
	    switch (start[1]) {
	    case 't':
		*lexemePtr = STR_LT;
		return 2;
	    case 'e':
		*lexemePtr = STR_LEQ;
		return 2;
	    }
	}
	break;
	
    case 'g':
	if ((numBytes > 1)
		&& ((numBytes == 2) || start[2] & 0x80 || !isalpha(UCHAR(start[2])))) {
	    switch (start[1]) {
	    case 't':
		*lexemePtr = STR_GT;
		return 2;
	    case 'e':
		*lexemePtr = STR_GEQ;
		return 2;
	    }
	}
	break;
    }

    literal = Tcl_NewObj();
    if (TclParseNumber(NULL, literal, NULL, start, numBytes, &end,
	    TCL_PARSE_NO_WHITESPACE) == TCL_OK) {
	if (end < start + numBytes && !TclIsBareword(*end)) {

................................................................................
}
 
/*
 *----------------------------------------------------------------------
 *
 * TclSortingOpCmd --
 *	Implements the commands:
 *		<, <=, >, >=, ==, eq, lt, le, gt, ge
 *	in the ::tcl::mathop namespace. These commands are defined for
 *	arbitrary number of arguments by computing the AND of the base
 *	operator applied to all neighbor argument pairs.
 *
 * Results:
 *	A standard Tcl return code and result left in interp.
 *

Changes to generic/tclCompile.c.

645
646
647
648
649
650
651









652
653
654
655
656
657
658
	/* The top word is the default, the next op4 words (min 1) are a key
	 * path into the dictionary just below the keys on the stack, and all
	 * those values are replaced by the value read out of that key-path
	 * (like [dict get]) except if there is no such key, when instead the
	 * default is pushed instead.
	 * Stack:  ... dict key1 ... keyN default => ... value */










    {NULL, 0, 0, 0, {OPERAND_NONE}}
};
 
/*
 * Prototypes for procedures defined later in this file:
 */







>
>
>
>
>
>
>
>
>







645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
	/* The top word is the default, the next op4 words (min 1) are a key
	 * path into the dictionary just below the keys on the stack, and all
	 * those values are replaced by the value read out of that key-path
	 * (like [dict get]) except if there is no such key, when instead the
	 * default is pushed instead.
	 * Stack:  ... dict key1 ... keyN default => ... value */

    {"strlt",		  1,   -1,         0,	{OPERAND_NONE}},
	/* String Less:			push (stknext < stktop) */
    {"strgt",		  1,   -1,         0,	{OPERAND_NONE}},
	/* String Greater:		push (stknext > stktop) */
    {"strle",		  1,   -1,         0,	{OPERAND_NONE}},
	/* String Less or equal:	push (stknext <= stktop) */
    {"strge",		  1,   -1,         0,	{OPERAND_NONE}},
	/* String Greater or equal:	push (stknext >= stktop) */

    {NULL, 0, 0, 0, {OPERAND_NONE}}
};
 
/*
 * Prototypes for procedures defined later in this file:
 */

Changes to generic/tclCompile.h.

814
815
816
817
818
819
820






821
822
823
824
825
826
827
    INST_LAPPEND_LIST_ARRAY,
    INST_LAPPEND_LIST_ARRAY_STK,
    INST_LAPPEND_LIST_STK,

    INST_CLOCK_READ,

    INST_DICT_GET_DEF,







    /* The last opcode */
    LAST_INST_OPCODE
};
 
/*
 * Table describing the Tcl bytecode instructions: their name (for displaying






>
>
>
>
>
>







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

    INST_CLOCK_READ,

    INST_DICT_GET_DEF,

	/* TIP 461 */
	INST_STR_LT,
	INST_STR_GT,
	INST_STR_LE,
	INST_STR_GE,

    /* The last opcode */
    LAST_INST_OPCODE
};
 
/*
 * Table describing the Tcl bytecode instructions: their name (for displaying

Changes to generic/tclEnsemble.c.

2704
2705
2706
2707
2708
2709
2710




2711
2712
2713
2714
2715
2716
2717
2718
		     * substituted part of the command (as a list) as their
		     * content!
		     */

		    if (isNew) {
			Tcl_Obj *cmdObj, *cmdPrefixObj;





			cmdObj = Tcl_NewStringObj(nsCmdName, -1);
			cmdPrefixObj = Tcl_NewListObj(1, &cmdObj);
			Tcl_SetHashValue(hPtr, cmdPrefixObj);
			Tcl_IncrRefCount(cmdPrefixObj);
		    }
		    break;
		}
	    }






>
>
>
>
|







2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
		     * substituted part of the command (as a list) as their
		     * content!
		     */

		    if (isNew) {
			Tcl_Obj *cmdObj, *cmdPrefixObj;

			TclNewObj(cmdObj);
			Tcl_AppendStringsToObj(cmdObj,
				ensemblePtr->nsPtr->fullName,
				(ensemblePtr->nsPtr->parentPtr ? "::" : ""),
				nsCmdName, NULL);
			cmdPrefixObj = Tcl_NewListObj(1, &cmdObj);
			Tcl_SetHashValue(hPtr, cmdPrefixObj);
			Tcl_IncrRefCount(cmdPrefixObj);
		    }
		    break;
		}
	    }

Changes to generic/tclExecute.c.

4871
4872
4873
4874
4875
4876
4877




4878
4879
4880
4881
4882
4883
4884
....
4901
4902
4903
4904
4905
4906
4907

4908
4909
4910

4911
4912
4913

4914
4915
4916

4917
4918
4919
4920
4921
4922
4923
     * -----------------------------------------------------------------
     *	   Start of string-related instructions.
     */

    case INST_STR_EQ:
    case INST_STR_NEQ:		/* String (in)equality check */
    case INST_STR_CMP:		/* String compare. */




    stringCompare:
	value2Ptr = OBJ_AT_TOS;
	valuePtr = OBJ_UNDER_TOS;

	{
	    int checkEq = ((*pc == INST_EQ) || (*pc == INST_NEQ)
		    || (*pc == INST_STR_EQ) || (*pc == INST_STR_NEQ));
................................................................................
		match = (match == 0);
		break;
	    case INST_STR_NEQ:
	    case INST_NEQ:
		match = (match != 0);
		break;
	    case INST_LT:

		match = (match < 0);
		break;
	    case INST_GT:

		match = (match > 0);
		break;
	    case INST_LE:

		match = (match <= 0);
		break;
	    case INST_GE:

		match = (match >= 0);
		break;
	    }
	}

	TRACE(("\"%.20s\" \"%.20s\" => %d\n", O2S(valuePtr), O2S(value2Ptr),
		(match < 0 ? -1 : match > 0 ? 1 : 0)));






>
>
>
>







 







>



>



>



>







4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
4885
4886
4887
4888
....
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
     * -----------------------------------------------------------------
     *	   Start of string-related instructions.
     */

    case INST_STR_EQ:
    case INST_STR_NEQ:		/* String (in)equality check */
    case INST_STR_CMP:		/* String compare. */
    case INST_STR_LT:
    case INST_STR_GT:
    case INST_STR_LE:
    case INST_STR_GE:
    stringCompare:
	value2Ptr = OBJ_AT_TOS;
	valuePtr = OBJ_UNDER_TOS;

	{
	    int checkEq = ((*pc == INST_EQ) || (*pc == INST_NEQ)
		    || (*pc == INST_STR_EQ) || (*pc == INST_STR_NEQ));
................................................................................
		match = (match == 0);
		break;
	    case INST_STR_NEQ:
	    case INST_NEQ:
		match = (match != 0);
		break;
	    case INST_LT:
	    case INST_STR_LT:
		match = (match < 0);
		break;
	    case INST_GT:
	    case INST_STR_GT:
		match = (match > 0);
		break;
	    case INST_LE:
	    case INST_STR_LE:
		match = (match <= 0);
		break;
	    case INST_GE:
	    case INST_STR_GE:
		match = (match >= 0);
		break;
	    }
	}

	TRACE(("\"%.20s\" \"%.20s\" => %d\n", O2S(valuePtr), O2S(value2Ptr),
		(match < 0 ? -1 : match > 0 ? 1 : 0)));

Changes to generic/tclInt.h.

3948
3949
3950
3951
3952
3953
3954












3955
3956
3957
3958
3959
3960
3961
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileEqOpCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileStreqOpCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,












			    struct CompileEnv *envPtr);

MODULE_SCOPE int	TclCompileAssembleCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);

/*






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







3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileEqOpCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileStreqOpCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileStrLtOpCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileStrLeOpCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileStrGtOpCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);
MODULE_SCOPE int	TclCompileStrGeOpCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);

MODULE_SCOPE int	TclCompileAssembleCmd(Tcl_Interp *interp,
			    Tcl_Parse *parsePtr, Command *cmdPtr,
			    struct CompileEnv *envPtr);

/*

Changes to generic/tclStrToD.c.

3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
....
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
....
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
....
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
    /*
     * b = bw * 2**b2 * 5**b5
     * mminus = 5**m5
     */

    TclInitBignumFromWideUInt(&b, bw);
    mp_init_set_int(&mminus, 1);
    MulPow5(&b, b5, &b);
    mp_mul_2d(&b, b2, &b);

    /*
     * Adjust if the logarithm was guessed wrong.
     */

................................................................................
    /*
     * b = bw * 2**b2 * 5**b5
     * S = 2**s2 * 5*s5
     */

    TclInitBignumFromWideUInt(&b, bw);
    mp_mul_2d(&b, b2, &b);
    mp_init_set_int(&S, 1);
    MulPow5(&S, s5, &S); mp_mul_2d(&S, s2, &S);

    /*
     * Handle the case where we guess the position of the decimal point wrong.
     */

    if (mp_cmp_mag(&b, &S) == MP_LT) {
................................................................................
	--k;
    }

    /*
     * mminus = 2**m2minus * 5**m5
     */

    mp_init_set_int(&mminus, minit);
    mp_mul_2d(&mminus, m2minus, &mminus);
    if (m2plus > m2minus) {
	mp_init_copy(&mplus, &mminus);
	mp_mul_2d(&mplus, m2plus-m2minus, &mplus);
    }

    /*
................................................................................
     * b = bw * 2**b2 * 5**b5
     * S = 2**s2 * 5*s5
     */

    mp_init_multi(&dig, NULL);
    TclInitBignumFromWideUInt(&b, bw);
    mp_mul_2d(&b, b2, &b);
    mp_init_set_int(&S, 1);
    MulPow5(&S, s5, &S); mp_mul_2d(&S, s2, &S);

    /*
     * Handle the case where we guess the position of the decimal point wrong.
     */

    if (mp_cmp_mag(&b, &S) == MP_LT) {






|







 







|







 







|







 







|







3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
....
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
....
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
....
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
    /*
     * b = bw * 2**b2 * 5**b5
     * mminus = 5**m5
     */

    TclInitBignumFromWideUInt(&b, bw);
    mp_init_set(&mminus, 1);
    MulPow5(&b, b5, &b);
    mp_mul_2d(&b, b2, &b);

    /*
     * Adjust if the logarithm was guessed wrong.
     */

................................................................................
    /*
     * b = bw * 2**b2 * 5**b5
     * S = 2**s2 * 5*s5
     */

    TclInitBignumFromWideUInt(&b, bw);
    mp_mul_2d(&b, b2, &b);
    mp_init_set(&S, 1);
    MulPow5(&S, s5, &S); mp_mul_2d(&S, s2, &S);

    /*
     * Handle the case where we guess the position of the decimal point wrong.
     */

    if (mp_cmp_mag(&b, &S) == MP_LT) {
................................................................................
	--k;
    }

    /*
     * mminus = 2**m2minus * 5**m5
     */

    mp_init_set(&mminus, minit);
    mp_mul_2d(&mminus, m2minus, &mminus);
    if (m2plus > m2minus) {
	mp_init_copy(&mplus, &mminus);
	mp_mul_2d(&mplus, m2plus-m2minus, &mplus);
    }

    /*
................................................................................
     * b = bw * 2**b2 * 5**b5
     * S = 2**s2 * 5*s5
     */

    mp_init_multi(&dig, NULL);
    TclInitBignumFromWideUInt(&b, bw);
    mp_mul_2d(&b, b2, &b);
    mp_init_set(&S, 1);
    MulPow5(&S, s5, &S); mp_mul_2d(&S, s2, &S);

    /*
     * Handle the case where we guess the position of the decimal point wrong.
     */

    if (mp_cmp_mag(&b, &S) == MP_LT) {

Changes to tests/expr.test.

128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
...
406
407
408
409
410
411
412




















413
414
415
416
417
418
419
....
7157
7158
7159
7160
7161
7162
7163



















7164
7165
7166
7167










































































































7168





7169
7170
7171







7172
7173
7174
7175
7176
7177
    global xxx
    set xxx ""
    12days 1 1 1
    set result [string length $xxx]
    unset xxx
    return $result
}

# start of tests

catch {unset a b i x}

test expr-1.1 {TclCompileExprCmd: no expression} {
    list [catch {expr  } msg] $msg
} {1 {wrong # args: should be "expr arg ?arg ...?"}}
................................................................................
} -returnCodes error -match glob -result *
test expr-8.34 {expr edge cases} -body {
    expr {1E+}
} -returnCodes error -match glob -result *
test expr-8.35 {expr edge cases} -body {
    expr {1ea}
} -returnCodes error -match glob -result *





















test expr-9.1 {CompileRelationalExpr: just shift expr} {expr 3<<2} 12
test expr-9.2 {CompileRelationalExpr: just shift expr} {expr 0xff>>2} 63
test expr-9.3 {CompileRelationalExpr: just shift expr} {expr -1>>2} -1
test expr-9.4 {CompileRelationalExpr: just shift expr} {expr {1<<3}} 8
test expr-9.5 {CompileRelationalExpr: shift expr producing LONG_MIN} {
    expr {int(1<<63)}
................................................................................
} {
	set a [list one two three]
	list [expr {$a eq {}}] [expr {$a < {}}] [expr {$a > {}}] [
		string match {*no string representation*} [
		::tcl::unsupported::representation $a]]
} {0 0 1 1}






















# cleanup
if {[info exists a]} {










































































































    unset a





}
catch {unset min}
catch {unset max}







::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:






|







 







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







 







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

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






128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
...
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
....
7177
7178
7179
7180
7181
7182
7183
7184
7185
7186
7187
7188
7189
7190
7191
7192
7193
7194
7195
7196
7197
7198
7199
7200
7201
7202
7203
7204


7205
7206
7207
7208
7209
7210
7211
7212
7213
7214
7215
7216
7217
7218
7219
7220
7221
7222
7223
7224
7225
7226
7227
7228
7229
7230
7231
7232
7233
7234
7235
7236
7237
7238
7239
7240
7241
7242
7243
7244
7245
7246
7247
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
7267
7268
7269
7270
7271
7272
7273
7274
7275
7276
7277
7278
7279
7280
7281
7282
7283
7284
7285
7286
7287
7288
7289
7290
7291
7292
7293
7294
7295
7296
7297
7298
7299
7300
7301
7302
7303
7304
7305
7306
7307
7308
7309
7310
7311
7312
7313
7314
7315
7316
7317


7318
7319
7320
7321
7322
7323
7324
7325
7326
7327
7328
7329
7330
    global xxx
    set xxx ""
    12days 1 1 1
    set result [string length $xxx]
    unset xxx
    return $result
}
 
# start of tests

catch {unset a b i x}

test expr-1.1 {TclCompileExprCmd: no expression} {
    list [catch {expr  } msg] $msg
} {1 {wrong # args: should be "expr arg ?arg ...?"}}
................................................................................
} -returnCodes error -match glob -result *
test expr-8.34 {expr edge cases} -body {
    expr {1E+}
} -returnCodes error -match glob -result *
test expr-8.35 {expr edge cases} -body {
    expr {1ea}
} -returnCodes error -match glob -result *
test expr-8.36 {CompileEqualtyExpr: string comparison ops} {
    set x 012
    set y 0x0
    list [expr {$x < $y}] [expr {$x lt $y}] [expr {$x lt $x}]
} {0 1 0}
test expr-8.37 {CompileEqualtyExpr: string comparison ops} {
    set x 012
    set y 0x0
    list [expr {$x <= $y}] [expr {$x le $y}] [expr {$x le $x}]
} {0 1 1}
test expr-8.38 {CompileEqualtyExpr: string comparison ops} {
    set x 012
    set y 0x0
    list [expr {$x > $y}] [expr {$x gt $y}] [expr {$x gt $x}]
} {1 0 0}
test expr-8.39 {CompileEqualtyExpr: string comparison ops} {
    set x 012
    set y 0x0
    list [expr {$x >= $y}] [expr {$x ge $y}] [expr {$x ge $x}]
} {1 0 1}

test expr-9.1 {CompileRelationalExpr: just shift expr} {expr 3<<2} 12
test expr-9.2 {CompileRelationalExpr: just shift expr} {expr 0xff>>2} 63
test expr-9.3 {CompileRelationalExpr: just shift expr} {expr -1>>2} -1
test expr-9.4 {CompileRelationalExpr: just shift expr} {expr {1<<3}} 8
test expr-9.5 {CompileRelationalExpr: shift expr producing LONG_MIN} {
    expr {int(1<<63)}
................................................................................
} {
	set a [list one two three]
	list [expr {$a eq {}}] [expr {$a < {}}] [expr {$a > {}}] [
		string match {*no string representation*} [
		::tcl::unsupported::representation $a]]
} {0 0 1 1}

foreach func {isfinite isinf isnan isnormal issubnormal} {
    test expr-53.1.$func {float classification: basic arg handling} -body {
	expr ${func}()
    } -returnCodes error -result "too few arguments for math function \"$func\""
    test expr-53.2.$func {float classification: basic arg handling} -body {
	expr ${func}(1,2)
    } -returnCodes error -result "too many arguments for math function \"$func\""
    test expr-53.3.$func {float classification: basic arg handling} -body {
	expr ${func}(true)
    } -returnCodes error -result {expected number but got "true"}
    test expr-53.4.$func {float classification: basic arg handling} -body {
	expr ${func}("gorp")
    } -returnCodes error -result {expected number but got "gorp"}
    test expr-53.5.$func {float classification: basic arg handling} -body {
	expr ${func}(1.0)
    } -match glob -result *
    test expr-53.6.$func {float classification: basic arg handling} -body {
	expr ${func}(0x123)
    } -match glob -result *
}



test expr-54.0 {float classification: isfinite} {expr {isfinite(1.0)}} 1
test expr-54.1 {float classification: isfinite} {expr {isfinite(-1.0)}} 1
test expr-54.2 {float classification: isfinite} {expr {isfinite(0.0)}} 1
test expr-54.3 {float classification: isfinite} {expr {isfinite(-0.0)}} 1
test expr-54.4 {float classification: isfinite} {expr {isfinite(1/Inf)}} 1
test expr-54.5 {float classification: isfinite} {expr {isfinite(-1/Inf)}} 1
test expr-54.6 {float classification: isfinite} {expr {isfinite(1e-314)}} 1
test expr-54.7 {float classification: isfinite} {expr {isfinite(inf)}} 0
test expr-54.8 {float classification: isfinite} {expr {isfinite(-inf)}} 0
test expr-54.9 {float classification: isfinite} {expr {isfinite(NaN)}} 0

test expr-55.0 {float classification: isinf} {expr {isinf(1.0)}} 0
test expr-55.1 {float classification: isinf} {expr {isinf(-1.0)}} 0
test expr-55.2 {float classification: isinf} {expr {isinf(0.0)}} 0
test expr-55.3 {float classification: isinf} {expr {isinf(-0.0)}} 0
test expr-55.4 {float classification: isinf} {expr {isinf(1/Inf)}} 0
test expr-55.5 {float classification: isinf} {expr {isinf(-1/Inf)}} 0
test expr-55.6 {float classification: isinf} {expr {isinf(1e-314)}} 0
test expr-55.7 {float classification: isinf} {expr {isinf(inf)}} 1
test expr-55.8 {float classification: isinf} {expr {isinf(-inf)}} 1
test expr-55.9 {float classification: isinf} {expr {isinf(NaN)}} 0

test expr-56.0 {float classification: isnan} {expr {isnan(1.0)}} 0
test expr-56.1 {float classification: isnan} {expr {isnan(-1.0)}} 0
test expr-56.2 {float classification: isnan} {expr {isnan(0.0)}} 0
test expr-56.3 {float classification: isnan} {expr {isnan(-0.0)}} 0
test expr-56.4 {float classification: isnan} {expr {isnan(1/Inf)}} 0
test expr-56.5 {float classification: isnan} {expr {isnan(-1/Inf)}} 0
test expr-56.6 {float classification: isnan} {expr {isnan(1e-314)}} 0
test expr-56.7 {float classification: isnan} {expr {isnan(inf)}} 0
test expr-56.8 {float classification: isnan} {expr {isnan(-inf)}} 0
test expr-56.9 {float classification: isnan} {expr {isnan(NaN)}} 1

test expr-57.0 {float classification: isnormal} {expr {isnormal(1.0)}} 1
test expr-57.1 {float classification: isnormal} {expr {isnormal(-1.0)}} 1
test expr-57.2 {float classification: isnormal} {expr {isnormal(0.0)}} 0
test expr-57.3 {float classification: isnormal} {expr {isnormal(-0.0)}} 0
test expr-57.4 {float classification: isnormal} {expr {isnormal(1/Inf)}} 0
test expr-57.5 {float classification: isnormal} {expr {isnormal(-1/Inf)}} 0
test expr-57.6 {float classification: isnormal} {expr {isnormal(1e-314)}} 0
test expr-57.7 {float classification: isnormal} {expr {isnormal(inf)}} 0
test expr-57.8 {float classification: isnormal} {expr {isnormal(-inf)}} 0
test expr-57.9 {float classification: isnormal} {expr {isnormal(NaN)}} 0

test expr-58.0 {float classification: issubnormal} {expr {issubnormal(1.0)}} 0
test expr-58.1 {float classification: issubnormal} {expr {issubnormal(-1.0)}} 0
test expr-58.2 {float classification: issubnormal} {expr {issubnormal(0.0)}} 0
test expr-58.3 {float classification: issubnormal} {expr {issubnormal(-0.0)}} 0
test expr-58.4 {float classification: issubnormal} {expr {issubnormal(1/Inf)}} 0
test expr-58.5 {float classification: issubnormal} {expr {issubnormal(-1/Inf)}} 0
test expr-58.6 {float classification: issubnormal} {expr {issubnormal(1e-314)}} 1
test expr-58.7 {float classification: issubnormal} {expr {issubnormal(inf)}} 0
test expr-58.8 {float classification: issubnormal} {expr {issubnormal(-inf)}} 0
test expr-58.9 {float classification: issubnormal} {expr {issubnormal(NaN)}} 0

test expr-59.0 {float classification: fpclassify} {fpclassify 1.0} normal
test expr-59.1 {float classification: fpclassify} {fpclassify -1.0} normal
test expr-59.2 {float classification: fpclassify} {fpclassify 0.0} zero
test expr-59.3 {float classification: fpclassify} {fpclassify -0.0} zero
test expr-59.4 {float classification: fpclassify} {fpclassify [expr 1/Inf]} zero
test expr-59.5 {float classification: fpclassify} {fpclassify [expr -1/Inf]} zero
test expr-59.6 {float classification: fpclassify} {fpclassify 1e-314} subnormal
test expr-59.7 {float classification: fpclassify} {fpclassify inf} infinite
test expr-59.8 {float classification: fpclassify} {fpclassify -inf} infinite
test expr-59.9 {float classification: fpclassify} {fpclassify NaN} nan
test expr-59.10 {float classification: fpclassify} -returnCodes error -body {
    fpclassify
} -result {wrong # args: should be "fpclassify floatValue"}
test expr-59.11 {float classification: fpclassify} -returnCodes error -body {
    fpclassify a b
} -result {wrong # args: should be "fpclassify floatValue"}
test expr-59.12 {float classification: fpclassify} -returnCodes error -body {
    fpclassify gorp
} -result {expected number but got "gorp"}

test expr-60.1 {float classification: basic arg handling} -body {
    expr isunordered()
} -returnCodes error -result {too few arguments for math function "isunordered"}
test expr-60.2 {float classification: basic arg handling} -body {
    expr isunordered(1)
} -returnCodes error -result {too few arguments for math function "isunordered"}
test expr-60.3 {float classification: basic arg handling} -body {
    expr {isunordered(1, 2, 3)}
} -returnCodes error -result {too many arguments for math function "isunordered"}
test expr-60.4 {float classification: basic arg handling} -body {
    expr {isunordered(true, 1.0)}
} -returnCodes error -result {expected number but got "true"}
test expr-60.5 {float classification: basic arg handling} -body {
    expr {isunordered("gorp", 1.0)}
} -returnCodes error -result {expected number but got "gorp"}
test expr-60.6 {float classification: basic arg handling} -body {
    expr {isunordered(0x123, 1.0)}
} -match glob -result *
test expr-60.7 {float classification: basic arg handling} -body {
    expr {isunordered(1.0, true)}
} -returnCodes error -result {expected number but got "true"}
test expr-60.8 {float classification: basic arg handling} -body {
    expr {isunordered(1.0, "gorp")}
} -returnCodes error -result {expected number but got "gorp"}
test expr-60.9 {float classification: basic arg handling} -body {
    expr {isunordered(1.0, 0x123)}
} -match glob -result *

# Big matrix of comparisons, but it's just a binary isinf()
set values {1.0 -1.0 0.0 -0.0 1e-314 Inf -Inf NaN}
set results {0 0 0 0 0 0 0 1}
set ctr 0
foreach v1 $values r1 $results {
    foreach v2 $values r2 $results {
	test expr-61.[incr ctr] "float classification: isunordered($v1,$v2)" {
	    expr {isunordered($v1, $v2)}
	} [expr {$r1 || $r2}]
    }


}
unset -nocomplain values results ctr
 
# cleanup
unset -nocomplain a
unset -nocomplain min
unset -nocomplain max
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:

Changes to tests/info.test.

651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
    catch {namespace delete x}
} -body {
    namespace eval x info vars foo
} -cleanup {
    namespace delete x
} -result {}

set functions {abs acos asin atan atan2 bool ceil cos cosh double entier exp floor fmod hypot int isqrt log log10 max min pow rand round sin sinh sqrt srand tan tanh wide}
# Check whether the extra testing functions are defined...
if {!([catch {expr T1()} msg] && ($msg eq {invalid command name "tcl::mathfunc::T1"}))} {
    set functions "T1 T2 T3 $functions"  ;# A lazy way of prepending!
}
test info-20.1 {info functions option} {info functions sin} sin
test info-20.2 {info functions option} {lsort [info functions]} $functions
test info-20.3 {info functions option} {






|







651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
    catch {namespace delete x}
} -body {
    namespace eval x info vars foo
} -cleanup {
    namespace delete x
} -result {}

set functions {abs acos asin atan atan2 bool ceil cos cosh double entier exp floor fmod hypot int isfinite isinf isnan isnormal isqrt issubnormal isunordered log log10 max min pow rand round sin sinh sqrt srand tan tanh wide}
# Check whether the extra testing functions are defined...
if {!([catch {expr T1()} msg] && ($msg eq {invalid command name "tcl::mathfunc::T1"}))} {
    set functions "T1 T2 T3 $functions"  ;# A lazy way of prepending!
}
test info-20.1 {info functions option} {info functions sin} sin
test info-20.2 {info functions option} {lsort [info functions]} $functions
test info-20.3 {info functions option} {

Changes to tests/mathop.test.

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
....
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
        set res2 [lindex $results $i+1]
        if {$res1 ne $res2} {
            return "$i:($res1 != $res2)"
        }
    }
    return [lindex $results 0]
}

# start of tests

namespace eval ::testmathop {
    namespace path ::tcl::mathop
    variable op ;# stop surprises!

    test mathop-1.1 {compiled +} { + } 0
................................................................................
    lappend res [TestOp - 0 -9223372036854775808]         ;# -2**63
    lappend res [TestOp / -9223372036854775808 -1]
    lappend res [TestOp * 2147483648 2]
    lappend res [TestOp * 9223372036854775808 2]
    set res
} [list 2147483648 9223372036854775808 9223372036854775808 4294967296 18446744073709551616]









































if 0 {
    # Compare ops to expr bytecodes
    namespace import ::tcl::mathop::*
    proc _X {a b c} {
        set x [+ $a [- $b $c]]
        set y [expr {$a + ($b - $c)}]
        set z [< $a $b $c]
    }
    set ::tcl_traceCompile 2
    _X 3 4 5
    set ::tcl_traceCompile 0
}

# cleanup
namespace delete ::testmathop
namespace delete ::testmathop2
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:






|







 







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












|









91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
....
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
        set res2 [lindex $results $i+1]
        if {$res1 ne $res2} {
            return "$i:($res1 != $res2)"
        }
    }
    return [lindex $results 0]
}
 
# start of tests

namespace eval ::testmathop {
    namespace path ::tcl::mathop
    variable op ;# stop surprises!

    test mathop-1.1 {compiled +} { + } 0
................................................................................
    lappend res [TestOp - 0 -9223372036854775808]         ;# -2**63
    lappend res [TestOp / -9223372036854775808 -1]
    lappend res [TestOp * 2147483648 2]
    lappend res [TestOp * 9223372036854775808 2]
    set res
} [list 2147483648 9223372036854775808 9223372036854775808 4294967296 18446744073709551616]

test mathop-27.1 {lt operator} {::tcl::mathop::lt} 1
test mathop-27.2 {lt operator} {::tcl::mathop::lt a} 1
test mathop-27.3 {lt operator} {::tcl::mathop::lt a b} 1
test mathop-27.4 {lt operator} {::tcl::mathop::lt b a} 0
test mathop-27.5 {lt operator} {::tcl::mathop::lt a a} 0
test mathop-27.6 {lt operator} {::tcl::mathop::lt a b c} 1
test mathop-27.7 {lt operator} {::tcl::mathop::lt b a c} 0
test mathop-27.8 {lt operator} {::tcl::mathop::lt a c b} 0
test mathop-27.9 {lt operator} {::tcl::mathop::lt 012 0x0} 1

test mathop-28.1 {le operator} {::tcl::mathop::le} 1
test mathop-28.2 {le operator} {::tcl::mathop::le a} 1
test mathop-28.3 {le operator} {::tcl::mathop::le a b} 1
test mathop-28.4 {le operator} {::tcl::mathop::le b a} 0
test mathop-28.5 {le operator} {::tcl::mathop::le a a} 1
test mathop-28.6 {le operator} {::tcl::mathop::le a b c} 1
test mathop-28.7 {le operator} {::tcl::mathop::le b a c} 0
test mathop-28.8 {le operator} {::tcl::mathop::le a c b} 0
test mathop-28.9 {le operator} {::tcl::mathop::le 012 0x0} 1

test mathop-29.1 {gt operator} {::tcl::mathop::gt} 1
test mathop-29.2 {gt operator} {::tcl::mathop::gt a} 1
test mathop-29.3 {gt operator} {::tcl::mathop::gt a b} 0
test mathop-29.4 {gt operator} {::tcl::mathop::gt b a} 1
test mathop-29.5 {gt operator} {::tcl::mathop::gt a a} 0
test mathop-29.6 {gt operator} {::tcl::mathop::gt c b a} 1
test mathop-29.7 {gt operator} {::tcl::mathop::gt b a c} 0
test mathop-29.8 {gt operator} {::tcl::mathop::gt a c b} 0
test mathop-29.9 {gt operator} {::tcl::mathop::gt 0x0 012} 1

test mathop-30.1 {ge operator} {::tcl::mathop::ge} 1
test mathop-30.2 {ge operator} {::tcl::mathop::ge a} 1
test mathop-30.3 {ge operator} {::tcl::mathop::ge a b} 0
test mathop-30.4 {ge operator} {::tcl::mathop::ge b a} 1
test mathop-30.5 {ge operator} {::tcl::mathop::ge a a} 1
test mathop-30.6 {ge operator} {::tcl::mathop::ge c b a} 1
test mathop-30.7 {ge operator} {::tcl::mathop::ge b a c} 0
test mathop-30.8 {ge operator} {::tcl::mathop::ge a c b} 0
test mathop-30.9 {ge operator} {::tcl::mathop::ge 0x0 012} 1

if 0 {
    # Compare ops to expr bytecodes
    namespace import ::tcl::mathop::*
    proc _X {a b c} {
        set x [+ $a [- $b $c]]
        set y [expr {$a + ($b - $c)}]
        set z [< $a $b $c]
    }
    set ::tcl_traceCompile 2
    _X 3 4 5
    set ::tcl_traceCompile 0
}
 
# cleanup
namespace delete ::testmathop
namespace delete ::testmathop2
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:

Changes to tests/namespace.test.

1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
....
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
....
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
....
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337













3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
	proc x2 {} {format 2}
	proc x3 {} {format 3}
	namespace ensemble create
    }
    list [ns x0 z] [ns x1] [ns x2] [ns x3]
} -cleanup {
    namespace delete ns
} -result {{1 z} 1 2 3}
test namespace-42.8 {
    ensembles: [Bug 1670091], panic due to pointer to a deallocated List
    struct.
} -setup {
    proc demo args {}
    variable target [list [namespace which demo] x]
    proc trial args {variable target; string length $target}
................................................................................
    set result {}
    lappend result [catch {ns a b c} msg] $msg
    lappend result [catch {ns a b c} msg] $msg
    lappend result [catch {ns b c d} msg] $msg
    lappend result [catch {ns c d e} msg] $msg
    lappend result [catch {ns Magic foo bar spong wibble} msg] $msg
    list $result [lsort [info commands ::ns::*]] $log [namespace delete ns]
} {{0 2 0 2 0 2 0 2 1 {unknown or protected subcommand "Magic"}} {::ns::Magic ::ns::a ::ns::b ::ns::c} {{making a} {running a b c} {running a b c} {making b} {running b c d} {making c} {running c d e} {unknown Magic - args = foo bar spong wibble}} {}}
test namespace-47.2 {ensemble: unknown handler} {
    namespace eval ns {
	namespace export {[a-z]*}
	proc Magic {ensemble subcmd args} {
	    error foobar
	}
	namespace ensemble create -unknown ::ns::Magic
................................................................................
} -cleanup {
    namespace delete ns
} -result\
   {0 0\
    1 {wrong # args: should be "ns z1 x a1"}\
    1 {wrong # args: should be "ns z2 x a1 a2"}\
    1 {wrong # args: should be "ns z2 x a1 a2"}\
    1 {wrong # args: should be "z0"}\
    0 {1 v}\
    1 {wrong # args: should be "ns v x z2 a2"}\
    0 {2 v v2}}
test namespace-53.11 {ensembles: nested rewrite} -setup {
    namespace eval ns {
	namespace export x
	namespace eval x {
................................................................................
	    return [lsort $gone]
	} finally {
	    namespace delete ::testing
	}
    }
} {::testing::abc::def ::testing::abc::ghi}

test namespace-56.4 {bug 16fe1b5807: names starting with ":"} {
namespace eval : {
    namespace ensemble create
    namespace export *
    proc p1 {} {
	    return 16fe1b5807
    }
}

: p1
} 16fe1b5807













 
# cleanup
catch {rename cmd1 {}}
catch {unset l}
catch {unset msg}
catch {unset trigger}
namespace delete {*}[namespace children :: test_ns_*]
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:






|







 







|







 







|







 







|










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













1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
....
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
....
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
....
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
	proc x2 {} {format 2}
	proc x3 {} {format 3}
	namespace ensemble create
    }
    list [ns x0 z] [ns x1] [ns x2] [ns x3]
} -cleanup {
    namespace delete ns
} -result {{1 ::ns::x0::z} 1 2 3}
test namespace-42.8 {
    ensembles: [Bug 1670091], panic due to pointer to a deallocated List
    struct.
} -setup {
    proc demo args {}
    variable target [list [namespace which demo] x]
    proc trial args {variable target; string length $target}
................................................................................
    set result {}
    lappend result [catch {ns a b c} msg] $msg
    lappend result [catch {ns a b c} msg] $msg
    lappend result [catch {ns b c d} msg] $msg
    lappend result [catch {ns c d e} msg] $msg
    lappend result [catch {ns Magic foo bar spong wibble} msg] $msg
    list $result [lsort [info commands ::ns::*]] $log [namespace delete ns]
} {{0 2 0 2 0 2 0 2 1 {unknown or protected subcommand "Magic"}} {::ns::Magic ::ns::a ::ns::b ::ns::c} {{making a} {running ::ns::a b c} {running ::ns::a b c} {making b} {running ::ns::b c d} {making c} {running ::ns::c d e} {unknown Magic - args = foo bar spong wibble}} {}}
test namespace-47.2 {ensemble: unknown handler} {
    namespace eval ns {
	namespace export {[a-z]*}
	proc Magic {ensemble subcmd args} {
	    error foobar
	}
	namespace ensemble create -unknown ::ns::Magic
................................................................................
} -cleanup {
    namespace delete ns
} -result\
   {0 0\
    1 {wrong # args: should be "ns z1 x a1"}\
    1 {wrong # args: should be "ns z2 x a1 a2"}\
    1 {wrong # args: should be "ns z2 x a1 a2"}\
    1 {wrong # args: should be "::ns::x::z0"}\
    0 {1 v}\
    1 {wrong # args: should be "ns v x z2 a2"}\
    0 {2 v v2}}
test namespace-53.11 {ensembles: nested rewrite} -setup {
    namespace eval ns {
	namespace export x
	namespace eval x {
................................................................................
	    return [lsort $gone]
	} finally {
	    namespace delete ::testing
	}
    }
} {::testing::abc::def ::testing::abc::ghi}

test namespace-56.4 {bug 16fe1b5807: names starting with ":"} knownBug {
namespace eval : {
    namespace ensemble create
    namespace export *
    proc p1 {} {
	    return 16fe1b5807
    }
}

: p1
} 16fe1b5807

test namespace-56.5 {Bug 8b9854c3d8} -setup {
    namespace eval namespace-56.5 {
	proc cmd {} {string match ::* [lindex [[string cat info] level 0] 0]}
	namespace export *
	namespace ensemble create
    }
} -body {
    namespace-56.5 cmd
} -cleanup {
    namespace delete namespace-56.5
} -result 1

 
# cleanup
catch {rename cmd1 {}}
catch {unset l}
catch {unset msg}
catch {unset trigger}
namespace delete {*}[namespace children :: test_ns_*]
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End: