]>
git.saurik.com Git - apple/security.git/blob - SecuritySNACCRuntime/c++-lib/c++/asn-real.cpp
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
19 // file: .../c++-lib/src/asn-real.C - AsnReal (ASN.1 REAL) type
23 // Copyright (C) 1992 Michael Sample and the University of British Columbia
25 // This library is free software; you can redistribute it and/or
26 // modify it provided that this copyright/license information is retained
29 // If you modify this file, you must clearly indicate your changes.
31 // This source code is distributed in the hope that it will be
32 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
33 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
35 // $Header: /cvs/root/Security/SecuritySNACCRuntime/c++-lib/c++/Attic/asn-real.cpp,v 1.4 2002/03/21 05:38:45 dmitch Exp $
36 // $Log: asn-real.cpp,v $
37 // Revision 1.4 2002/03/21 05:38:45 dmitch
38 // Radar 2868524: no more setjmp/longjmp in SNACC-generated code.
40 // Revision 1.3.44.1 2002/03/20 00:36:50 dmitch
41 // Radar 2868524: SNACC-generated code now uses throw/catch instead of setjmp/longjmp.
43 // Revision 1.3 2001/06/27 23:09:15 dmitch
44 // Pusuant to Radar 2664258, avoid all cerr-based output in NDEBUG configuration.
46 // Revision 1.2 2001/06/21 21:57:00 dmitch
47 // Avoid global const PLUS_INFINITY, MINUS_INFINITY
49 // Revision 1.1.1.1 2001/05/18 23:14:06 mb
50 // Move from private repository to open source repository
52 // Revision 1.3 2001/05/05 00:59:19 rmurphy
53 // Adding darwin license headers
55 // Revision 1.2 2000/06/08 20:05:36 dmitch
56 // Mods for X port. These files are actually machine generated and probably don't need to be in CVS....
58 // Revision 1.1.1.1 2000/03/09 01:00:06 rmurphy
59 // Base Fortissimo Tree
61 // Revision 1.3 1999/03/21 02:07:37 mb
62 // Added Copy to every AsnType.
64 // Revision 1.2 1999/02/26 00:23:40 mb
67 // Revision 1.1 1999/02/25 05:21:53 mb
68 // Added snacc c++ library
70 // Revision 1.7 1997/02/28 13:39:46 wan
71 // Modifications collected for new version 1.3: Bug fixes, tk4.2.
73 // Revision 1.6 1995/08/17 15:27:19 rj
74 // recognize and return "±inf" for PLUS-INFINITY/MINUS-INFINITY.
76 // Revision 1.5 1995/07/24 20:29:24 rj
77 // #if TCL ... #endif wrapped into #if META ... #endif
79 // call constructor with additional pdu and create arguments.
81 // changed `_' to `-' in file names.
83 // Revision 1.4 1995/02/18 17:01:49 rj
84 // denote a long if we want a long.
85 // make the code work on little endian CPUs.
86 // ported to work with CPU/compiler combinations providing 64 bit longs.
88 // Revision 1.3 1994/10/08 04:18:29 rj
89 // code for meta structures added (provides information about the generated code itself).
91 // code for Tcl interface added (makes use of the above mentioned meta code).
93 // virtual inline functions (the destructor, the Clone() function, BEnc(), BDec() and Print()) moved from inc/*.h to src/*.C because g++ turns every one of them into a static non-inline function in every file where the .h file gets included.
95 // made Print() const (and some other, mainly comparison functions).
97 // several `unsigned long int' turned into `size_t'.
99 // Revision 1.2 1994/08/28 10:01:18 rj
100 // comment leader fixed.
102 // Revision 1.1 1994/08/28 09:21:07 rj
103 // first check-in. for a list of changes to the snacc-1.1 distribution please refer to the ChangeLog.
105 #include "asn-config.h"
108 #include "asn-type.h"
109 #include "asn-real.h"
111 #ifndef IEEE_REAL_LIB
112 /* ieee functions (in case not in math.h)*/
114 extern int iszero ( double );
115 //extern int isinf (double);
116 //extern int signbit (double);
117 extern int ilogb ( double );
118 //extern double scalbn (double, int);
122 double AsnPlusInfinity ();
123 double AsnMinusInfinity ();
125 #define ENC_PLUS_INFINITY 0x40
126 #define ENC_MINUS_INFINITY 0x41
128 #define REAL_BINARY 0x80
129 #define REAL_SIGN 0x40
130 #define REAL_EXPLEN_MASK 0x03
131 #define REAL_EXPLEN_1 0x00
132 #define REAL_EXPLEN_2 0x01
133 #define REAL_EXPLEN_3 0x02
134 #define REAL_EXPLEN_LONG 0x03
135 #define REAL_FACTOR_MASK 0x0c
136 #define REAL_BASE_MASK 0x30
137 #define REAL_BASE_2 0x00
138 #define REAL_BASE_8 0x10
139 #define REAL_BASE_16 0x20
141 AsnType
* AsnReal :: Clone () const
146 AsnType
* AsnReal :: Copy () const
148 return new AsnReal (* this );
151 // Returns the smallest octet length needed to hold the given long int value
153 SignedIntOctetLen ( long int val
)
155 unsigned long int mask
= ( 0x7f80 L
<< (( sizeof ( long int ) - 2 ) * 8 ));
156 unsigned int retVal
= sizeof ( long int );
159 val
= val
^ (~ 0L ); /* XOR val with all 1's */
161 while (( retVal
> 1 ) && (( val
& mask
) == 0 ))
169 } /* SignedIntOctetLen */
175 // Returns the PLUS INFINITY in double format
176 // This assumes that a C++ double is an IEEE double.
177 // The bits for IEEE double PLUS INFINITY are
178 // 0x7ff0000000000000
179 double AsnPlusInfinity ()
183 unsigned char * c
= ( unsigned char *)& d
;
207 return 1.7976931348623158e+308 ;
208 #endif /* _IBM_ENC_ */
209 } /* AsnPlusInfinity */
211 double AsnMinusInfinity ()
213 return - AsnPlusInfinity ();
216 #if SIZEOF_DOUBLE != 8
217 #error oops: doubles are expected to be 8 bytes in size!
221 * Use this routine if you system/compiler represents doubles in the IEEE format.
223 AsnLen
AsnReal :: BEncContent ( BUF_TYPE b
)
228 unsigned long mantissa
, val
, * p
;
230 #elif SIZEOF_LONG == 4
232 unsigned long int * first4
;
233 unsigned long int * second4
;
235 #error long neither 8 nor 4 bytes in size?
238 /* no contents for 0.0 reals */
239 if ( value
== 0.0 ) /* all bits zero, disregarding top/sign bit */
244 * this part assumes that sizeof (long) == sizeof (double) == 8
245 * It shouldn't be endian-dependent but I haven't verified that
248 p
= ( unsigned long *) & value
;
251 isNeg
= ( val
>> 63 ) & 1 ;
252 /* special real values for +/- oo */
256 b
. PutByteRvs ( ENC_MINUS_INFINITY
);
258 b
. PutByteRvs ( ENC_PLUS_INFINITY
);
261 else /* encode a binary real value */
263 exponent
= ( val
>> 52 ) & 0x7ff ;
264 mantissa
= ( val
& 0xfffffffffffff L
) | 0x10000000000000 L
;
266 for ( i
= 0 ; i
< 7 ; i
++)
268 b
. PutByteRvs ( mantissa
& 0xff );
271 exponent
-= ( 1023 + 52 );
273 #elif SIZEOF_LONG == 4
275 * this part assumes that sizeof (long) == 4 and
276 * that sizeof (double) == 8
280 * Sv-----------v----- rest is mantissa
281 * -------------------------------------------
283 * -------------------------------------------
286 * sign bit is 1 if real is < 0
287 * exponent is an 11 bit unsigned value (subtract 1023 to get correct exp value)
288 * decimal pt implied before mantissa (ie mantissa is all fractional)
289 * and implicit 1 bit to left of decimal
291 * when given NaN (not a number - ie oo/oo) it encodes the wrong value
292 * instead of checking for the error. If you want to check for it,
293 * a NaN is any sign bit with a max exponent (all bits a 1) followed
294 * by any non-zero mantissa. (a zero mantissa is used for infinity)
298 first4
= ( unsigned long int *) ( dbl
= ( unsigned char *) & value
);
299 second4
= ( unsigned long int *) ( dbl
+ sizeof ( long int ));
301 /* no contents for 0.0 reals */
302 if ( value
== 0.0 ) /* all bits zero, disregarding top/sign bit */
305 isNeg
= dbl
[ 0 ] & 0x80 ;
307 /* special real values for +/- oo */
308 if (((* first4
& 0x7fffffff ) == 0x7ff00000 ) && (* second4
== 0 ))
311 b
. PutByteRvs ( ENC_MINUS_INFINITY
);
313 b
. PutByteRvs ( ENC_PLUS_INFINITY
);
317 else /* encode a binary real value */
319 exponent
= (((* first4
) >> 20 ) & 0x07ff );
321 /* write the mantissa (N value) */
322 b
. PutSegRvs (( char *)( dbl
+ 2 ), sizeof ( double )- 2 );
325 * The rightmost 4 bits of a double 2nd octet are the
326 * most sig bits of the mantissa.
327 * write the most signficant byte of the asn1 real manitssa,
328 * adding implicit bit to 'left of decimal' if not de-normalized
329 * (de normalized if exponent == 0)
331 * if the double is not in de-normalized form subtract 1023
332 * from the exponent to get proper signed exponent.
334 * for both the normalized and de-norm forms
335 * correct the exponent by subtracting 52 since:
336 * 1. mantissa is 52 bits in the double (56 in ASN.1 REAL form)
337 * 2. implicit decimal at the beginning of double's mantissa
338 * 3. ASN.1 REAL's implicit decimal is after its mantissa
339 * so converting the double mantissa to the ASN.1 form has the
340 * effect of multiplying it by 2^52. Subtracting 52 from the
341 * exponent corrects this.
343 if ( exponent
== 0 ) /* de-normalized - no implicit 1 to left of dec.*/
345 b
. PutByteRvs ( dbl
[ 1 ] & 0x0f );
350 b
. PutByteRvs (( dbl
[ 1 ] & 0x0f ) | 0x10 ); /* 0x10 adds implicit bit */
351 exponent
-= ( 1023 + 52 );
355 #error long neither 8 nor 4 bytes in size?
358 /* write the exponent */
359 b
. PutByteRvs ( exponent
& 0xff );
360 b
. PutByteRvs ( exponent
>> 8 );
362 /* write format octet */
363 /* bb is 00 since base is 2 so do nothing */
364 /* ff is 00 since no other shifting is nec */
366 b
. PutByteRvs ( REAL_BINARY
| REAL_EXPLEN_2
| REAL_SIGN
);
368 b
. PutByteRvs ( REAL_BINARY
| REAL_EXPLEN_2
);
370 return sizeof ( double ) + 2 ;
375 } /* AsnReal::BEncContent */
377 #else /* IEEE_REAL_FMT not def */
381 // Returns the PLUS INFINITY in double format
382 // this assumes you have the IEEE functions in
384 double AsnPlusInfinity ()
387 } /* AsnPlusInfinity */
389 double AsnMinusInfinity ()
391 return - AsnPlusInfinity ();
394 // This routine uses the ieee library routines to encode
395 // this AsnReal's double value
396 AsnLen
AsnReal :: BEncContent ( BUF_TYPE b
)
401 unsigned int truncatedMantissa
;
405 unsigned char buf
[ sizeof ( double )];
407 unsigned char firstOctet
;
409 /* no contents for 0.0 reals */
413 /* special real values for +/- oo */
416 if ( signbit ( value
)) /* neg */
417 b
. PutByteRvs ( ENC_MINUS_INFINITY
);
419 b
. PutByteRvs ( ENC_PLUS_INFINITY
);
423 else /* encode a binary real value */
430 exponent
= ilogb ( value
);
432 /* get the absolute value of the mantissa (subtract 1 to make < 1) */
433 mantissa
= scalbn ( fabs ( value
), - exponent
- 1 );
436 tmpMantissa
= mantissa
;
438 /* convert mantissa into an unsigned integer */
439 for ( i
= 0 ; i
< sizeof ( double ); i
++)
441 /* normalizied so shift 8 bits worth to the left of the decimal */
442 tmpMantissa
*= ( 1 << 8 );
444 /* grab only (octet sized) the integer part */
445 truncatedMantissa
= ( unsigned int ) tmpMantissa
;
447 /* remove part to left of decimal now for next iteration */
448 tmpMantissa
-= truncatedMantissa
;
450 /* write into tmp buffer */
451 buf
[ i
] = truncatedMantissa
;
453 /* keep track of last non zero octet so can zap trailing zeros */
454 if ( truncatedMantissa
)
459 * write format octet (first octet of content)
463 * 1 in bit#1 means binary rep
464 * 1 in bit#2 means the mantissa is neg, 0 pos
465 * bb is the base: 65 base
471 * ff is the Value of F where Mantissa = sign x N x 2^F
472 * FF can be one of 0 to 3 inclusive. (used to save re-alignment)
474 * ee is the length of the exponent: 21 length
481 * encoded binary real value looks like
484 * --------------------------------------------------------
485 * |1Sbbffee| exponent (2's comp) | N (unsigned int) |
486 * --------------------------------------------------------
489 firstOctet
= REAL_BINARY
;
491 firstOctet
|= REAL_SIGN
;
493 /* bb is 00 since base is 2 so do nothing */
494 /* ff is 00 since no other shifting is nec */
497 * get exponent calculate its encoded length
498 * Note that the process of converting the mantissa
499 * double to an int shifted the decimal mantissaLen * 8
500 * to the right - so correct that here
502 exponent
++; /* compensate for trick to put mantissa < 1 */
503 exponent
-= ( mantissaLen
* 8 );
504 expLen
= SignedIntOctetLen ( exponent
);
509 firstOctet
|= REAL_EXPLEN_1
;
512 firstOctet
|= REAL_EXPLEN_2
;
515 firstOctet
|= REAL_EXPLEN_3
;
518 firstOctet
|= REAL_EXPLEN_LONG
;
522 encLen
= mantissaLen
+ expLen
+ 1 ;
524 /* write the mantissa (N value) */
525 b
. PutSegRvs (( char *) buf
, mantissaLen
);
527 /* write the exponent */
528 for ( i
= expLen
; i
> 0 ; i
--)
530 b
. PutByteRvs ( exponent
);
534 /* write the exponents length if nec */
538 b
. PutByteRvs ( expLen
);
541 /* write the format octet */
542 b
. PutByteRvs ( firstOctet
);
547 } /* AsnReal::BEncContent */
549 #else /* neither IEEE_REAL_FMT or IEEE_REAL_LIB are def */
552 // Returns the PLUS INFINITY in double format
553 // This assumes that a C++ double is an IEEE double.
554 // The bits for IEEE double PLUS INFINITY are
555 // 0x7ff0000000000000
556 // NOTE: this is a guess - you should set this up for
558 double AsnPlusInfinity ()
564 c
= ( unsigned char *)& d
;
567 for ( i
= 2 ; i
< sizeof ( double ); i
++)
570 } /* AsnPlusInfinity */
572 double AsnMinusInfinity ()
574 return - AsnPlusInfinity ();
578 * Encodes the content of an ASN.1 REAL value to the given buffer.
579 * This version of the routine does not assume an IEEE double rep.
580 * or the existence of the IEEE library routines. Uses old style
583 AsnLen
AsnReal :: BEncContent ( BUF_TYPE b
)
585 unsigned long int encLen
;
588 unsigned int truncatedMantissa
;
592 unsigned char buf
[ sizeof ( double )];
593 unsigned i
, mantissaLen
;
594 unsigned char firstOctet
;
596 /* no contents for 0.0 reals */
600 /* special real values for +/- oo */
601 if ( value
== MINUS_INFINITY
)
603 b
. PutByteRvs ( ENC_MINUS_INFINITY
);
606 else if ( value
== PLUS_INFINITY
)
608 b
. PutByteRvs ( ENC_PLUS_INFINITY
);
611 else /* encode a binary real value */
614 * this is what frexp gets from value
615 * value == mantissa * 2^exponent
616 * where 0.5 <= |manitissa| < 1.0
618 mantissa
= frexp ( value
, & exponent
);
620 /* set sign and make mantissa = | mantissa | */
630 tmpMantissa
= mantissa
;
632 /* convert mantissa into an unsigned integer */
633 for ( i
= 0 ; i
< sizeof ( double ); i
++)
635 /* normalizied so shift 8 bits worth to the left of the decimal */
636 tmpMantissa
*= ( 1 << 8 );
638 /* grab only (octet sized) the integer part */
639 truncatedMantissa
= ( unsigned int ) tmpMantissa
;
641 /* remove part to left of decimal now for next iteration */
642 tmpMantissa
-= truncatedMantissa
;
644 /* write into tmp buffer */
645 buf
[ i
] = truncatedMantissa
;
647 /* keep track of last non zero octet so can zap trailing zeros */
648 if ( truncatedMantissa
)
653 * write format octet (first octet of content)
657 * 1 in bit#1 means binary rep
658 * 1 in bit#2 means the mantissa is neg, 0 pos
659 * bb is the base: 65 base
665 * ff is the Value of F where Mantissa = sign x N x 2^F
666 * FF can be one of 0 to 3 inclusive. (used to save re-alignment)
668 * ee is the length of the exponent: 21 length
675 * encoded binary real value looks like
678 * --------------------------------------------------------
679 * |1Sbbffee| exponent (2's comp) | N (unsigned int) |
680 * --------------------------------------------------------
683 firstOctet
= REAL_BINARY
;
685 firstOctet
|= REAL_SIGN
;
687 /* bb is 00 since base is 2 so do nothing */
688 /* ff is 00 since no other shifting is nec */
691 * get exponent calculate its encoded length
692 * Note that the process of converting the mantissa
693 * double to an int shifted the decimal mantissaLen * 8
694 * to the right - so correct that here
696 exponent
-= ( mantissaLen
* 8 );
697 expLen
= SignedIntOctetLen ( exponent
);
702 firstOctet
|= REAL_EXPLEN_1
;
705 firstOctet
|= REAL_EXPLEN_2
;
708 firstOctet
|= REAL_EXPLEN_3
;
711 firstOctet
|= REAL_EXPLEN_LONG
;
715 encLen
= mantissaLen
+ expLen
+ 1 ;
717 /* write the mantissa (N value) */
718 b
. PutSegRvs (( char *) buf
, mantissaLen
);
720 /* write the exponent */
721 for ( i
= expLen
; i
> 0 ; i
--)
723 b
. PutByteRvs ( exponent
);
727 /* write the exponents length if nec */
731 b
. PutByteRvs ( expLen
);
734 /* write the format octet */
735 b
. PutByteRvs ( firstOctet
);
740 } /* AsnReal:BEncContent */
748 // Decode a REAL value's content from the given buffer.
749 // places the result in this object.
750 void AsnReal :: BDecContent ( BUF_TYPE b
, AsnTag tagId
, AsnLen elmtLen
, AsnLen
& bytesDecoded
, ENV_TYPE env
)
752 unsigned char firstOctet
;
753 unsigned char firstExpOctet
;
758 long int exponent
= 0 ;
769 firstOctet
= b
. GetByte ();
773 if ( firstOctet
== ENC_PLUS_INFINITY
)
774 value
= PLUS_INFINITY
;
775 else if ( firstOctet
== ENC_MINUS_INFINITY
)
776 value
= MINUS_INFINITY
;
779 Asn1Error
<< "AsnReal::BDecContent: ERROR - unrecognized 1 octet length real number" << endl
;
780 #if SNACC_EXCEPTION_ENABLE
781 SnaccExcep :: throwMe (- 18 );
789 if ( firstOctet
& REAL_BINARY
)
791 firstExpOctet
= b
. GetByte ();
792 if ( firstExpOctet
& 0x80 )
794 switch ( firstOctet
& REAL_EXPLEN_MASK
)
798 exponent
= ( exponent
<< 8 ) | firstExpOctet
;
803 exponent
= ( exponent
<< 16 ) | ((( unsigned long int ) firstExpOctet
) << 8 ) | b
. GetByte ();
808 exponent
= ( exponent
<< 16 ) | ((( unsigned long int ) firstExpOctet
) << 8 ) | b
. GetByte ();
809 exponent
= ( exponent
<< 8 ) | b
. GetByte ();
812 default : /* long form */
813 expLen
= firstExpOctet
+ 1 ;
815 firstExpOctet
= b
. GetByte ();
816 if ( firstExpOctet
& 0x80 )
817 exponent
= (- 1 << 8 ) | firstExpOctet
;
819 exponent
= firstExpOctet
;
820 for (; i
> 0 ; firstExpOctet
--)
821 exponent
= ( exponent
<< 8 ) | b
. GetByte ();
826 for ( i
= 1 + expLen
; i
< elmtLen
; i
++)
829 mantissa
+= b
. GetByte ();
832 /* adjust N by scaling factor */
833 mantissa
*= ( 1 <<(( firstOctet
& REAL_FACTOR_MASK
) >> 2 ));
835 switch ( firstOctet
& REAL_BASE_MASK
)
850 Asn1Error
<< "AsnReal::BDecContent: ERROR - unsupported base for a binary real number." << endl
;
851 #if SNACC_EXCEPTION_ENABLE
852 SnaccExcep :: throwMe (- 19 );
863 value
= mantissa
* pow (( double ) base
, ( double ) exponent
);
865 if ( firstOctet
& REAL_SIGN
)
868 bytesDecoded
+= elmtLen
;
870 else /* decimal version */
872 Asn1Error
<< "AsnReal::BDecContent: ERROR - decimal REAL form is not currently supported" << endl
;
873 #if SNACC_EXCEPTION_ENABLE
874 SnaccExcep :: throwMe (- 20 );
881 } /* AsnInt::BDecContent */
883 AsnLen
AsnReal :: BEnc ( BUF_TYPE b
)
887 l
+= BEncDefLen ( b
, l
);
888 l
+= BEncTag1 ( b
, UNIV
, PRIM
, REAL_TAG_CODE
);
892 void AsnReal :: BDec ( BUF_TYPE b
, AsnLen
& bytesDecoded
, ENV_TYPE env
)
895 if ( BDecTag ( b
, bytesDecoded
, env
) != MAKE_TAG_ID ( UNIV
, PRIM
, REAL_TAG_CODE
))
897 Asn1Error
<< "AsnReal::BDec: ERROR tag on REAL is wrong." << endl
;
898 #if SNACC_EXCEPTION_ENABLE
899 SnaccExcep :: throwMe (- 58 );
904 elmtLen
= BDecLen ( b
, bytesDecoded
, env
);
906 BDecContent ( b
, MAKE_TAG_ID ( UNIV
, PRIM
, REAL_TAG_CODE
), elmtLen
, bytesDecoded
, env
);
909 void AsnReal :: Print ( ostream
& os
) const
918 const AsnRealTypeDesc
AsnReal :: _desc ( NULL
, NULL
, false , AsnTypeDesc :: REAL
, NULL
);
920 const AsnTypeDesc
* AsnReal :: _getdesc () const
927 int AsnReal :: TclGetVal ( Tcl_Interp
* interp
) const
929 if ( value
== PLUS_INFINITY
)
930 strcpy ( interp
-> result
, "+inf" );
931 else if ( value
== MINUS_INFINITY
)
932 strcpy ( interp
-> result
, "-inf" );
934 sprintf ( interp
-> result
, " %g " , value
);
938 int AsnReal :: TclSetVal ( Tcl_Interp
* interp
, const char * valstr
)
942 if (! strcmp ( valstr
, "+inf" ))
943 valval
= PLUS_INFINITY
;
944 else if (! strcmp ( valstr
, "-inf" ))
945 valval
= MINUS_INFINITY
;
946 else if ( Tcl_GetDouble ( interp
, ( char *) valstr
, & valval
) != TCL_OK
)