wasCSharpSQLite – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 #undef DEBUG
2 /*
3 * Util.java --
4 *
5 * This class provides useful Tcl utility methods.
6 *
7 * Copyright (c) 1997 Cornell University.
8 * Copyright (c) 1997-1999 by Sun Microsystems, Inc.
9 *
10 * See the file "license.terms" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 *
13 * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
14 *
15 * RCS @(#) $Id: Util.java,v 1.10 2002/05/16 22:53:45 mdejong Exp $
16 */
17 using System;
18 using System.Text;
19 using Regexp = sunlabs.brazil.util.regexp.Regexp;
20 namespace tcl.lang
21 {
22  
23 public class Util
24 {
25 public static int ActualPlatform
26 {
27 get
28 {
29 if ( Util.Windows )
30 {
31 return JACL.PLATFORM_WINDOWS;
32 }
33 if ( Util.Mac )
34 {
35 return JACL.PLATFORM_MAC;
36 }
37 return JACL.PLATFORM_UNIX;
38 }
39  
40 }
41 public static bool Unix
42 {
43 get
44 {
45 if ( Mac || Windows )
46 {
47 return false;
48 }
49 return true;
50 }
51  
52 }
53 public static bool Mac
54 {
55 get
56 {
57 return false;
58 }
59  
60 }
61 public static bool Windows
62 {
63 get
64 {
65 // TODO .NET ist always Windows now
66 return true;
67 }
68  
69 }
70  
71 internal const int TCL_DONT_USE_BRACES = 1;
72 internal const int USE_BRACES = 2;
73 internal const int BRACES_UNMATCHED = 4;
74  
75 // Some error messages.
76  
77 internal const string intTooBigCode = "ARITH IOVERFLOW {integer value too large to represent}";
78 internal const string fpTooBigCode = "ARITH OVERFLOW {floating-point value too large to represent}";
79  
80 // This table below is used to convert from ASCII digits to a
81 // numerical equivalent. It maps from '0' through 'z' to integers
82 // (100 for non-digit characters).
83  
84 internal static char[] cvtIn = new char[] { (char)( 0 ), (char)( 1 ), (char)( 2 ), (char)( 3 ), (char)( 4 ), (char)( 5 ), (char)( 6 ), (char)( 7 ), (char)( 8 ), (char)( 9 ), (char)( 100 ), (char)( 100 ), (char)( 100 ), (char)( 100 ), (char)( 100 ), (char)( 100 ), (char)( 100 ), (char)( 10 ), (char)( 11 ), (char)( 12 ), (char)( 13 ), (char)( 14 ), (char)( 15 ), (char)( 16 ), (char)( 17 ), (char)( 18 ), (char)( 19 ), (char)( 20 ), (char)( 21 ), (char)( 22 ), (char)( 23 ), (char)( 24 ), (char)( 25 ), (char)( 26 ), (char)( 27 ), (char)( 28 ), (char)( 29 ), (char)( 30 ), (char)( 31 ), (char)( 32 ), (char)( 33 ), (char)( 34 ), (char)( 35 ), (char)( 100 ), (char)( 100 ), (char)( 100 ), (char)( 100 ), (char)( 100 ), (char)( 100 ), (char)( 10 ), (char)( 11 ), (char)( 12 ), (char)( 13 ), (char)( 14 ), (char)( 15 ), (char)( 16 ), (char)( 17 ), (char)( 18 ), (char)( 19 ), (char)( 20 ), (char)( 21 ), (char)( 22 ), (char)( 23 ), (char)( 24 ), (char)( 25 ), (char)( 26 ), (char)( 27 ), (char)( 28 ), (char)( 29 ), (char)( 30 ), (char)( 31 ), (char)( 32 ), (char)( 33 ), (char)( 34 ), (char)( 35 ) };
85  
86 // Largest possible base 10 exponent. Any
87 // exponent larger than this will already
88 // produce underflow or overflow, so there's
89 // no need to worry about additional digits.
90  
91 internal const int maxExponent = 511;
92  
93 // Table giving binary powers of 10. Entry
94 // is 10^2^i. Used to convert decimal
95 // exponents into floating-point numbers.
96  
97 internal static readonly double[] powersOf10 = new double[] { 10.0, 100.0, 1.0e4, 1.0e8, 1.0e16, 1.0e32, 1.0e64, 1.0e128, 1.0e256 };
98  
99 // Default precision for converting floating-point values to strings.
100  
101 internal const int DEFAULT_PRECISION = 12;
102  
103 // The following variable determine the precision used when converting
104 // floating-point values to strings. This information is linked to all
105 // of the tcl_precision variables in all interpreters inside a JVM via
106 // PrecTraceProc.
107 //
108 // Note: since multiple threads may change precision concurrently, race
109 // conditions may occur.
110 //
111 // It should be modified only by the PrecTraceProc class.
112  
113 internal static int precision;
114 private Util()
115 {
116 // Do nothing. This should never be called.
117 }
118 internal static StrtoulResult strtoul( string s, int start, int base_ )
119 // Base for conversion. Must be less than 37. If 0,
120 // then the base is chosen from the leading characters
121 // of string: "0x" means hex, "0" means octal,
122 // anything else means decimal.
123 {
124 long result = 0;
125 int digit;
126 bool anyDigits = false;
127 int len = s.Length;
128 int i = start;
129 char c;
130  
131 // Skip any leading blanks.
132  
133 while ( i < len && System.Char.IsWhiteSpace( s[i] ) )
134 {
135 i++;
136 }
137 if ( i >= len )
138 {
139 return new StrtoulResult( 0, 0, TCL.INVALID_INTEGER );
140 }
141  
142 // If no base was provided, pick one from the leading characters
143 // of the string.
144  
145 if ( base_ == 0 )
146 {
147 c = s[i];
148 if ( c == '0' )
149 {
150 if ( i < len - 1 )
151 {
152 i++;
153 c = s[i];
154 if ( c == 'x' || c == 'X' )
155 {
156 i += 1;
157 base_ = 16;
158 }
159 }
160 if ( base_ == 0 )
161 {
162 // Must set anyDigits here, otherwise "0" produces a
163 // "no digits" error.
164  
165 anyDigits = true;
166 base_ = 8;
167 }
168 }
169 else
170 {
171 base_ = 10;
172 }
173 }
174 else if ( base_ == 16 )
175 {
176 if ( i < len - 2 )
177 {
178 // Skip a leading "0x" from hex numbers.
179  
180 if ( ( s[i] == '0' ) && ( s[i + 1] == 'x' ) )
181 {
182 i += 2;
183 }
184 }
185 }
186  
187 long max = ( Int64.MaxValue / ( (long)base_ ) );
188 bool overflowed = false;
189  
190 for ( ; ; i += 1 )
191 {
192 if ( i >= len )
193 {
194 break;
195 }
196 digit = s[i] - '0';
197 if ( digit < 0 || digit > ( 'z' - '0' ) )
198 {
199 break;
200 }
201 digit = cvtIn[digit];
202 if ( digit >= base_ )
203 {
204 break;
205 }
206  
207 if ( result > max )
208 {
209 overflowed = true;
210 }
211  
212 result = result * base_ + digit;
213 anyDigits = true;
214 }
215  
216 // See if there were any digits at all.
217  
218 if ( !anyDigits )
219 {
220 return new StrtoulResult( 0, 0, TCL.INVALID_INTEGER );
221 }
222 else if ( overflowed )
223 {
224 return new StrtoulResult( 0, i, TCL.INTEGER_RANGE );
225 }
226 else
227 {
228 return new StrtoulResult( result, i, 0 );
229 }
230 }
231 internal static int getInt( Interp interp, string s )
232 {
233 int len = s.Length;
234 bool sign;
235 int i = 0;
236  
237 // Skip any leading blanks.
238  
239 while ( i < len && System.Char.IsWhiteSpace( s[i] ) )
240 {
241 i++;
242 }
243 if ( i >= len )
244 {
245 throw new TclException( interp, "expected integer but got \"" + s + "\"" );
246 }
247  
248 char c = s[i];
249 if ( c == '-' )
250 {
251 sign = true;
252 i += 1;
253 }
254 else
255 {
256 if ( c == '+' )
257 {
258 i += 1;
259 }
260 sign = false;
261 }
262  
263 StrtoulResult res = strtoul( s, i, 0 );
264 if ( res.errno < 0 )
265 {
266 if ( res.errno == TCL.INTEGER_RANGE )
267 {
268 if ( interp != null )
269 {
270 interp.setErrorCode( TclString.newInstance( intTooBigCode ) );
271 }
272 throw new TclException( interp, "integer value too large to represent" );
273 }
274 else
275 {
276 throw new TclException( interp, "expected integer but got \"" + s + "\"" + checkBadOctal( interp, s ) );
277 }
278 }
279 else if ( res.index < len )
280 {
281 for ( i = res.index; i < len; i++ )
282 {
283 if ( !System.Char.IsWhiteSpace( s[i] ) )
284 {
285 throw new TclException( interp, "expected integer but got \"" + s + "\"" + checkBadOctal( interp, s ) );
286 }
287 }
288 }
289  
290 if ( sign )
291 {
292 return (int)( -res.value );
293 }
294 else
295 {
296 return (int)( res.value );
297 }
298 }
299 internal static long getLong( Interp interp, string s )
300 {
301 int len = s.Length;
302 bool sign;
303 int i = 0;
304  
305 // Skip any leading blanks.
306  
307 while ( i < len && System.Char.IsWhiteSpace( s[i] ) )
308 {
309 i++;
310 }
311 if ( i >= len )
312 {
313 throw new TclException( interp, "expected integer but got \"" + s + "\"" );
314 }
315  
316 char c = s[i];
317 if ( c == '-' )
318 {
319 sign = true;
320 i += 1;
321 }
322 else
323 {
324 if ( c == '+' )
325 {
326 i += 1;
327 }
328 sign = false;
329 }
330  
331 StrtoulResult res = strtoul( s, i, 0 );
332 if ( res.errno < 0 )
333 {
334 if ( res.errno == TCL.INTEGER_RANGE )
335 {
336 if ( interp != null )
337 {
338 interp.setErrorCode( TclString.newInstance( intTooBigCode ) );
339 }
340 throw new TclException( interp, "integer value too large to represent" );
341 }
342 else
343 {
344 throw new TclException( interp, "expected integer but got \"" + s + "\"" + checkBadOctal( interp, s ) );
345 }
346 }
347 else if ( res.index < len )
348 {
349 for ( i = res.index; i < len; i++ )
350 {
351 if ( !System.Char.IsWhiteSpace( s[i] ) )
352 {
353 throw new TclException( interp, "expected integer but got \"" + s + "\"" + checkBadOctal( interp, s ) );
354 }
355 }
356 }
357  
358 if ( sign )
359 {
360 return (long)( -res.value );
361 }
362 else
363 {
364 return (long)( res.value );
365 }
366 }
367 internal static int getIntForIndex( Interp interp, TclObject tobj, int endValue )
368 {
369 int length, offset;
370  
371 if ( tobj.InternalRep is TclInteger )
372 {
373 return TclInteger.get( interp, tobj );
374 }
375  
376  
377 string bytes = tobj.ToString();
378 length = bytes.Length;
379  
380 string intforindex_error = "bad index \"" + bytes + "\": must be integer or end?-integer?" + checkBadOctal( interp, bytes );
381  
382 // FIXME : should we replace this call to regionMatches with a generic strncmp?
383 if ( !( String.Compare( "end", 0, bytes, 0, ( length > 3 ) ? 3 : length ) == 0 ) )
384 {
385 try
386 {
387 offset = TclInteger.get( null, tobj );
388 }
389 catch ( TclException e )
390 {
391 throw new TclException( interp, "bad index \"" + bytes + "\": must be integer or end?-integer?" + checkBadOctal( interp, bytes ) );
392 }
393 return offset;
394 }
395  
396 if ( length <= 3 )
397 {
398 return endValue;
399 }
400 else if ( bytes[3] == '-' )
401 {
402 // This is our limited string expression evaluator
403  
404 offset = Util.getInt( interp, bytes.Substring( 3 ) );
405 return endValue + offset;
406 }
407 else
408 {
409 throw new TclException( interp, "bad index \"" + bytes + "\": must be integer or end?-integer?" + checkBadOctal( interp, bytes.Substring( 3 ) ) );
410 }
411 }
412 internal static string checkBadOctal( Interp interp, string value )
413 {
414 int p = 0;
415 int len = value.Length;
416  
417 // A frequent mistake is invalid octal values due to an unwanted
418 // leading zero. Try to generate a meaningful error message.
419  
420 while ( p < len && System.Char.IsWhiteSpace( value[p] ) )
421 {
422 p++;
423 }
424 if ( ( p < len ) && ( value[p] == '+' || value[p] == '-' ) )
425 {
426 p++;
427 }
428 if ( ( p < len ) && ( value[p] == '0' ) )
429 {
430 while ( ( p < len ) && System.Char.IsDigit( value[p] ) )
431 {
432 // INTL: digit.
433 p++;
434 }
435 while ( ( p < len ) && System.Char.IsWhiteSpace( value[p] ) )
436 {
437 // INTL: ISO space.
438 p++;
439 }
440 if ( p >= len )
441 {
442 // Reached end of string
443 if ( interp != null )
444 {
445 return " (looks like invalid octal number)";
446 }
447 }
448 }
449 return "";
450 }
451 internal static StrtodResult strtod( string s, int start )
452 // The index to the char where the number starts.
453 {
454 //bool sign;
455 char c;
456 int mantSize; // Number of digits in mantissa.
457 int decPt; // Number of mantissa digits BEFORE decimal
458 // point.
459 int len = s.Length;
460 int i = start;
461  
462 // Skip any leading blanks.
463  
464 while ( i < len && System.Char.IsWhiteSpace( s[i] ) )
465 {
466 i++;
467 }
468 if ( i >= len )
469 {
470 return new StrtodResult( 0, 0, TCL.INVALID_DOUBLE );
471 }
472  
473 c = s[i];
474 if ( c == '-' )
475 {
476 // sign = true;
477 i += 1;
478 }
479 else
480 {
481 if ( c == '+' )
482 {
483 i += 1;
484 }
485 // sign = false;
486 }
487  
488 // Count the number of digits in the mantissa (including the decimal
489 // point), and also locate the decimal point.
490  
491 bool maybeZero = true;
492 decPt = -1;
493 for ( mantSize = 0; ; mantSize += 1 )
494 {
495 c = CharAt( s, i, len );
496 if ( !System.Char.IsDigit( c ) )
497 {
498 if ( ( c != '.' ) || ( decPt >= 0 ) )
499 {
500 break;
501 }
502 decPt = mantSize;
503 }
504 if ( c != '0' && c != '.' )
505 {
506 maybeZero = false; // non zero digit found...
507 }
508 i++;
509 }
510  
511 // Skim off the exponent.
512  
513 if ( ( CharAt( s, i, len ) == 'E' ) || ( CharAt( s, i, len ) == 'e' ) )
514 {
515 i += 1;
516 if ( CharAt( s, i, len ) == '-' )
517 {
518 i += 1;
519 }
520 else if ( CharAt( s, i, len ) == '+' )
521 {
522 i += 1;
523 }
524  
525 while ( System.Char.IsDigit( CharAt( s, i, len ) ) )
526 {
527 i += 1;
528 }
529 }
530  
531 s = s.Substring( start, ( i ) - ( start ) );
532 double result = 0;
533  
534 try
535 {
536 result = System.Double.Parse( s, System.Globalization.NumberFormatInfo.InvariantInfo );
537 }
538 catch ( System.OverflowException e )
539 {
540 return new StrtodResult( 0, 0, TCL.DOUBLE_RANGE );
541 }
542 catch ( System.FormatException e )
543 {
544 return new StrtodResult( 0, 0, TCL.INVALID_DOUBLE );
545 }
546  
547 if ( ( result == System.Double.NegativeInfinity ) || ( result == System.Double.PositiveInfinity ) || ( result == 0.0 && !maybeZero ) )
548 {
549 return new StrtodResult( result, i, TCL.DOUBLE_RANGE );
550 }
551  
552 if ( result == System.Double.NaN )
553 {
554 return new StrtodResult( 0, 0, TCL.INVALID_DOUBLE );
555 }
556  
557 return new StrtodResult( result, i, 0 );
558 }
559 internal static char CharAt( string s, int index, int len )
560 {
561 if ( index >= 0 && index < len )
562 {
563 return s[index];
564 }
565 else
566 {
567 return '\x0000';
568 }
569 }
570 internal static double getDouble( Interp interp, string s )
571 {
572 int len = s.Length;
573 bool sign;
574 int i = 0;
575  
576 // Skip any leading blanks.
577  
578 while ( i < len && System.Char.IsWhiteSpace( s[i] ) )
579 {
580 i++;
581 }
582 if ( i >= len )
583 {
584 throw new TclException( interp, "expected floating-point number but got \"" + s + "\"" );
585 }
586  
587 char c = s[i];
588 if ( c == '-' )
589 {
590 sign = true;
591 i += 1;
592 }
593 else
594 {
595 if ( c == '+' )
596 {
597 i += 1;
598 }
599 sign = false;
600 }
601  
602 StrtodResult res = strtod( s, i );
603 if ( res.errno != 0 )
604 {
605 if ( res.errno == TCL.DOUBLE_RANGE )
606 {
607 if ( interp != null )
608 {
609 interp.setErrorCode( TclString.newInstance( fpTooBigCode ) );
610 }
611 throw new TclException( interp, "floating-point value too large to represent" );
612 }
613 else
614 {
615 throw new TclException( interp, "expected floating-point number but got \"" + s + "\"" );
616 }
617 }
618 else if ( res.index < len )
619 {
620 for ( i = res.index; i < len; i++ )
621 {
622 if ( !System.Char.IsWhiteSpace( s[i] ) )
623 {
624 throw new TclException( interp, "expected floating-point number but got \"" + s + "\"" );
625 }
626 }
627 }
628  
629 if ( sign )
630 {
631 return (double)( -res.value );
632 }
633 else
634 {
635 return (double)( res.value );
636 }
637 }
638 internal static string concat( int from, int to, TclObject[] argv )
639 // The CmdArgs.
640 {
641 StringBuilder sbuf;
642  
643 if ( from > argv.Length )
644 {
645 return "";
646 }
647 if ( to <= argv.Length )
648 {
649 to = argv.Length - 1;
650 }
651  
652 sbuf = new StringBuilder();
653 for ( int i = from; i <= to; i++ )
654 {
655  
656 string str = TrimLeft( argv[i].ToString() );
657 str = TrimRight( str );
658 if ( str.Length == 0 )
659 {
660 continue;
661 }
662 sbuf.Append( str );
663 if ( i < to )
664 {
665 sbuf.Append( " " );
666 }
667 }
668  
669 return sbuf.ToString().TrimEnd();
670 }
671 public static bool stringMatch( string str, string pat )
672 //Pattern which may contain special characters.
673 {
674 char[] strArr = str.ToCharArray();
675 char[] patArr = pat.ToCharArray();
676 int strLen = str.Length; // Cache the len of str.
677 int patLen = pat.Length; // Cache the len of pat.
678 int pIndex = 0; // Current index into patArr.
679 int sIndex = 0; // Current index into patArr.
680 char strch; // Stores current char in string.
681 char ch1; // Stores char after '[' in pat.
682 char ch2; // Stores look ahead 2 char in pat.
683 bool incrIndex = false; // If true it will incr both p/sIndex.
684  
685 while ( true )
686 {
687  
688 if ( incrIndex == true )
689 {
690 pIndex++;
691 sIndex++;
692 incrIndex = false;
693 }
694  
695 // See if we're at the end of both the pattern and the string.
696 // If so, we succeeded. If we're at the end of the pattern
697 // but not at the end of the string, we failed.
698  
699 if ( pIndex == patLen )
700 {
701 return sIndex == strLen;
702 }
703 if ( ( sIndex == strLen ) && ( patArr[pIndex] != '*' ) )
704 {
705 return false;
706 }
707  
708 // Check for a "*" as the next pattern character. It matches
709 // any substring. We handle this by calling ourselves
710 // recursively for each postfix of string, until either we
711 // match or we reach the end of the string.
712  
713 if ( patArr[pIndex] == '*' )
714 {
715 pIndex++;
716 if ( pIndex == patLen )
717 {
718 return true;
719 }
720 while ( true )
721 {
722 if ( stringMatch( str.Substring( sIndex ), pat.Substring( pIndex ) ) )
723 {
724 return true;
725 }
726 if ( sIndex == strLen )
727 {
728 return false;
729 }
730 sIndex++;
731 }
732 }
733  
734 // Check for a "?" as the next pattern character. It matches
735 // any single character.
736  
737 if ( patArr[pIndex] == '?' )
738 {
739 incrIndex = true;
740 continue;
741 }
742  
743 // Check for a "[" as the next pattern character. It is followed
744 // by a list of characters that are acceptable, or by a range
745 // (two characters separated by "-").
746  
747 if ( patArr[pIndex] == '[' )
748 {
749 pIndex++;
750 while ( true )
751 {
752 if ( ( pIndex == patLen ) || ( patArr[pIndex] == ']' ) )
753 {
754 return false;
755 }
756 if ( sIndex == strLen )
757 {
758 return false;
759 }
760 ch1 = patArr[pIndex];
761 strch = strArr[sIndex];
762 if ( ( ( pIndex + 1 ) != patLen ) && ( patArr[pIndex + 1] == '-' ) )
763 {
764 if ( ( pIndex += 2 ) == patLen )
765 {
766 return false;
767 }
768 ch2 = patArr[pIndex];
769 if ( ( ( ch1 <= strch ) && ( ch2 >= strch ) ) || ( ( ch1 >= strch ) && ( ch2 <= strch ) ) )
770 {
771 break;
772 }
773 }
774 else if ( ch1 == strch )
775 {
776 break;
777 }
778 pIndex++;
779 }
780  
781 for ( pIndex++; ( ( pIndex != patLen ) && ( patArr[pIndex] != ']' ) ); pIndex++ )
782 {
783 }
784 if ( pIndex == patLen )
785 {
786 pIndex--;
787 }
788 incrIndex = true;
789 continue;
790 }
791  
792 // If the next pattern character is '\', just strip off the '\'
793 // so we do exact matching on the character that follows.
794  
795 if ( patArr[pIndex] == '\\' )
796 {
797 pIndex++;
798 if ( pIndex == patLen )
799 {
800 return false;
801 }
802 }
803  
804 // There's no special character. Just make sure that the next
805 // characters of each string match.
806  
807 if ( ( sIndex == strLen ) || ( patArr[pIndex] != strArr[sIndex] ) )
808 {
809 return false;
810 }
811 incrIndex = true;
812 }
813 }
814 internal static string toTitle( string str )
815 // String to convert in place.
816 {
817 // Capitalize the first character and then lowercase the rest of the
818 // characters until we get to the end of string.
819  
820 int length = str.Length;
821 if ( length == 0 )
822 {
823 return "";
824 }
825 StringBuilder buf = new StringBuilder( length );
826 buf.Append( System.Char.ToUpper( str[0] ) );
827 buf.Append( str.Substring( 1 ).ToLower() );
828 return buf.ToString();
829 }
830 internal static bool regExpMatch( Interp interp, string inString, TclObject pattern )
831 {
832 Regexp r = TclRegexp.compile( interp, pattern, false );
833 return r.match( inString, (string[])null );
834 }
835 internal static void appendElement( Interp interp, StringBuilder sbuf, string s )
836 {
837 if ( sbuf.Length > 0 )
838 {
839 sbuf.Append( ' ' );
840 }
841  
842 int flags = scanElement( interp, s );
843 sbuf.Append( convertElement( s, flags ) );
844 }
845 internal static FindElemResult findElement( Interp interp, string s, int i, int len )
846 {
847 int openBraces = 0;
848 bool inQuotes = false;
849  
850 for ( ; i < len && System.Char.IsWhiteSpace( s[i] ); i++ )
851 {
852 ;
853 }
854 if ( i >= len )
855 {
856 return null;
857 }
858 char c = s[i];
859 if ( c == '{' )
860 {
861 openBraces = 1;
862 i++;
863 }
864 else if ( c == '"' )
865 {
866 inQuotes = true;
867 i++;
868 }
869 StringBuilder sbuf = new StringBuilder();
870  
871 while ( true )
872 {
873 if ( i >= len )
874 {
875 if ( openBraces != 0 )
876 {
877 throw new TclException( interp, "unmatched open brace in list" );
878 }
879 else if ( inQuotes )
880 {
881 throw new TclException( interp, "unmatched open quote in list" );
882 }
883 return new FindElemResult( i, sbuf.ToString(), openBraces );
884 }
885  
886 c = s[i];
887 switch ( c )
888 {
889  
890 // Open brace: don't treat specially unless the element is
891 // in braces. In this case, keep a nesting count.
892 case '{':
893 if ( openBraces != 0 )
894 {
895 openBraces++;
896 }
897 sbuf.Append( c );
898 i++;
899 break;
900  
901 // Close brace: if element is in braces, keep nesting
902 // count and quit when the last close brace is seen.
903  
904  
905 case '}':
906 if ( openBraces == 1 )
907 {
908 if ( i == len - 1 || System.Char.IsWhiteSpace( s[i + 1] ) )
909 {
910 return new FindElemResult( i + 1, sbuf.ToString(), openBraces );
911 }
912 else
913 {
914 int errEnd;
915 for ( errEnd = i + 1; errEnd < len; errEnd++ )
916 {
917 if ( System.Char.IsWhiteSpace( s[errEnd] ) )
918 {
919 break;
920 }
921 }
922 throw new TclException( interp, "list element in braces followed by \"" + s.Substring( i + 1, ( errEnd ) - ( i + 1 ) ) + "\" instead of space" );
923 }
924 }
925 else if ( openBraces != 0 )
926 {
927 openBraces--;
928 }
929 sbuf.Append( c );
930 i++;
931 break;
932  
933 // Backslash: skip over everything up to the end of the
934 // backslash sequence.
935  
936  
937 case '\\':
938 BackSlashResult bs = Interp.backslash( s, i, len );
939 if ( openBraces > 0 )
940 {
941 // Quotes are ignored in brace-quoted stuff
942  
943 sbuf.Append( s.Substring( i, ( bs.nextIndex ) - ( i ) ) );
944 }
945 else
946 {
947 sbuf.Append( bs.c );
948 }
949 i = bs.nextIndex;
950  
951 break;
952  
953 // Space: ignore if element is in braces or quotes; otherwise
954 // terminate element.
955  
956  
957 case ' ':
958 case '\f':
959 case '\n':
960 case '\r':
961 case '\t':
962 if ( ( openBraces == 0 ) && !inQuotes )
963 {
964 return new FindElemResult( i + 1, sbuf.ToString(), openBraces );
965 }
966 else
967 {
968 sbuf.Append( c );
969 i++;
970 }
971 break;
972  
973 // Double-quote: if element is in quotes then terminate it.
974  
975  
976 case '"':
977 if ( inQuotes )
978 {
979 if ( i == len - 1 || System.Char.IsWhiteSpace( s[i + 1] ) )
980 {
981 return new FindElemResult( i + 1, sbuf.ToString(), openBraces );
982 }
983 else
984 {
985 int errEnd;
986 for ( errEnd = i + 1; errEnd < len; errEnd++ )
987 {
988 if ( System.Char.IsWhiteSpace( s[errEnd] ) )
989 {
990 break;
991 }
992 }
993 throw new TclException( interp, "list element in quotes followed by \"" + s.Substring( i + 1, ( errEnd ) - ( i + 1 ) ) + "\" instead of space" );
994 }
995 }
996 else
997 {
998 sbuf.Append( c );
999 i++;
1000 }
1001 break;
1002  
1003  
1004 default:
1005 sbuf.Append( c );
1006 i++;
1007 break;
1008  
1009 }
1010 }
1011 }
1012 internal static int scanElement( Interp interp, string inString )
1013 {
1014 int flags, nestingLevel;
1015 char c;
1016 int len;
1017 int i;
1018  
1019 // This procedure and Tcl_ConvertElement together do two things:
1020 //
1021 // 1. They produce a proper list, one that will yield back the
1022 // argument strings when evaluated or when disassembled with
1023 // Tcl_SplitList. This is the most important thing.
1024 //
1025 // 2. They try to produce legible output, which means minimizing the
1026 // use of backslashes (using braces instead). However, there are
1027 // some situations where backslashes must be used (e.g. an element
1028 // like "{abc": the leading brace will have to be backslashed. For
1029 // each element, one of three things must be done:
1030 //
1031 // (a) Use the element as-is (it doesn't contain anything special
1032 // characters). This is the most desirable option.
1033 //
1034 // (b) Enclose the element in braces, but leave the contents alone.
1035 // This happens if the element contains embedded space, or if it
1036 // contains characters with special interpretation ($, [, ;, or \),
1037 // or if it starts with a brace or double-quote, or if there are
1038 // no characters in the element.
1039 //
1040 // (c) Don't enclose the element in braces, but add backslashes to
1041 // prevent special interpretation of special characters. This is a
1042 // last resort used when the argument would normally fall under case
1043 // (b) but contains unmatched braces. It also occurs if the last
1044 // character of the argument is a backslash or if the element contains
1045 // a backslash followed by newline.
1046 //
1047 // The procedure figures out how many bytes will be needed to store
1048 // the result (actually, it overestimates). It also collects
1049 // information about the element in the form of a flags word.
1050  
1051 nestingLevel = 0;
1052 flags = 0;
1053  
1054 i = 0;
1055 len = ( inString != null ? inString.Length : 0 );
1056 if ( len == 0 )
1057 {
1058 inString = '\x0000'.ToString();
1059  
1060 // FIXME : pizza compiler workaround
1061 // We really should be able to use the "\0" form but there
1062 // is a nasty bug in the pizza compiler shipped with kaffe
1063 // that causes "\0" to be read as the empty string.
1064  
1065 //string = "\0";
1066 }
1067  
1068 System.Diagnostics.Debug.WriteLine( "scanElement string is \"" + inString + "\"" );
1069  
1070 c = inString[i];
1071 if ( ( c == '{' ) || ( c == '"' ) || ( c == '\x0000' ) )
1072 {
1073 flags |= USE_BRACES;
1074 }
1075 for ( ; i < len; i++ )
1076 {
1077 System.Diagnostics.Debug.WriteLine( "getting char at index " + i );
1078 System.Diagnostics.Debug.WriteLine( "char is '" + inString[i] + "'" );
1079  
1080 c = inString[i];
1081 switch ( c )
1082 {
1083  
1084 case '{':
1085 nestingLevel++;
1086 break;
1087  
1088 case '}':
1089 nestingLevel--;
1090 if ( nestingLevel < 0 )
1091 {
1092 flags |= TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
1093 }
1094 break;
1095  
1096 case '[':
1097 case '$':
1098 case ';':
1099 case ' ':
1100 case '\f':
1101 case '\n':
1102 case '\r':
1103 case '\t':
1104 case (char)( 0x0b ):
1105  
1106 flags |= USE_BRACES;
1107 break;
1108  
1109 case '\\':
1110 if ( ( i >= len - 1 ) || ( inString[i + 1] == '\n' ) )
1111 {
1112 flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
1113 }
1114 else
1115 {
1116 BackSlashResult bs = Interp.backslash( inString, i, len );
1117  
1118 // Subtract 1 because the for loop will automatically
1119 // add one on the next iteration.
1120  
1121 i = ( bs.nextIndex - 1 );
1122 flags |= USE_BRACES;
1123 }
1124 break;
1125 }
1126 }
1127 if ( nestingLevel != 0 )
1128 {
1129 flags = TCL_DONT_USE_BRACES | BRACES_UNMATCHED;
1130 }
1131  
1132 return flags;
1133 }
1134 internal static string convertElement( string s, int flags )
1135 // Flags produced by ccanElement
1136 {
1137 int i = 0;
1138 char c;
1139 int len = ( s != null ? s.Length : 0 );
1140  
1141 // See the comment block at the beginning of the ScanElement
1142 // code for details of how this works.
1143  
1144 if ( ( (System.Object)s == null ) || ( s.Length == 0 ) || ( s[0] == '\x0000' ) )
1145 {
1146 return "{}";
1147 }
1148  
1149 StringBuilder sbuf = new StringBuilder();
1150  
1151 if ( ( ( flags & USE_BRACES ) != 0 ) && ( ( flags & TCL_DONT_USE_BRACES ) == 0 ) )
1152 {
1153 sbuf.Append( '{' );
1154 for ( i = 0; i < len; i++ )
1155 {
1156 sbuf.Append( s[i] );
1157 }
1158 sbuf.Append( '}' );
1159 }
1160 else
1161 {
1162 c = s[0];
1163 if ( c == '{' )
1164 {
1165 // Can't have a leading brace unless the whole element is
1166 // enclosed in braces. Add a backslash before the brace.
1167 // Furthermore, this may destroy the balance between open
1168 // and close braces, so set BRACES_UNMATCHED.
1169  
1170 sbuf.Append( '\\' );
1171 sbuf.Append( '{' );
1172 i++;
1173 flags |= BRACES_UNMATCHED;
1174 }
1175  
1176 for ( ; i < len; i++ )
1177 {
1178 c = s[i];
1179 switch ( c )
1180 {
1181  
1182 case ']':
1183 case '[':
1184 case '$':
1185 case ';':
1186 case ' ':
1187 case '\\':
1188 case '"':
1189 sbuf.Append( '\\' );
1190 break;
1191  
1192  
1193 case '{':
1194 case '}':
1195  
1196 if ( ( flags & BRACES_UNMATCHED ) != 0 )
1197 {
1198 sbuf.Append( '\\' );
1199 }
1200 break;
1201  
1202  
1203 case '\f':
1204 sbuf.Append( '\\' );
1205 sbuf.Append( 'f' );
1206 continue;
1207  
1208  
1209 case '\n':
1210 sbuf.Append( '\\' );
1211 sbuf.Append( 'n' );
1212 continue;
1213  
1214  
1215 case '\r':
1216 sbuf.Append( '\\' );
1217 sbuf.Append( 'r' );
1218 continue;
1219  
1220  
1221 case '\t':
1222 sbuf.Append( '\\' );
1223 sbuf.Append( 't' );
1224 continue;
1225  
1226 case (char)( 0x0b ):
1227  
1228 sbuf.Append( '\\' );
1229 sbuf.Append( 'v' );
1230 continue;
1231 }
1232  
1233 sbuf.Append( c );
1234 }
1235 }
1236  
1237 return sbuf.ToString();
1238 }
1239 internal static string TrimLeft( string str, string pattern )
1240 {
1241 int i, j;
1242 char c;
1243 int strLen = str.Length;
1244 int patLen = pattern.Length;
1245 bool done = false;
1246  
1247 for ( i = 0; i < strLen; i++ )
1248 {
1249 c = str[i];
1250 done = true;
1251 for ( j = 0; j < patLen; j++ )
1252 {
1253 if ( c == pattern[j] )
1254 {
1255 done = false;
1256 break;
1257 }
1258 }
1259 if ( done )
1260 {
1261 break;
1262 }
1263 }
1264 return str.Substring( i, ( strLen ) - ( i ) );
1265 }
1266 internal static string TrimLeft( string str )
1267 {
1268 return TrimLeft( str, " \n\t\r" );
1269 }
1270 internal static string TrimRight( string str, string pattern )
1271 {
1272 int last = str.Length - 1;
1273 char[] strArray = str.ToCharArray();
1274 int c;
1275  
1276 // Remove trailing characters...
1277  
1278 while ( last >= 0 )
1279 {
1280 c = strArray[last];
1281 if ( pattern.IndexOf( (System.Char)c ) == -1 )
1282 {
1283 break;
1284 }
1285 last--;
1286 }
1287 return str.Substring( 0, ( last + 1 ) - ( 0 ) );
1288 }
1289  
1290 internal static string TrimRight( string str )
1291 {
1292 return TrimRight( str, " \n\t\r" );
1293 }
1294 internal static bool getBoolean( Interp interp, string inString )
1295 {
1296 string s = inString.ToLower();
1297  
1298 // The length of 's' needs to be > 1 if it begins with 'o',
1299 // in order to compare between "on" and "off".
1300  
1301 if ( s.Length > 0 )
1302 {
1303 if ( "yes".StartsWith( s ) )
1304 {
1305 return true;
1306 }
1307 else if ( "no".StartsWith( s ) )
1308 {
1309 return false;
1310 }
1311 else if ( "true".StartsWith( s ) )
1312 {
1313 return true;
1314 }
1315 else if ( "false".StartsWith( s ) )
1316 {
1317 return false;
1318 }
1319 else if ( "on".StartsWith( s ) && s.Length > 1 )
1320 {
1321 return true;
1322 }
1323 else if ( "off".StartsWith( s ) && s.Length > 1 )
1324 {
1325 return false;
1326 }
1327 else if ( s.Equals( "0" ) )
1328 {
1329 return false;
1330 }
1331 else if ( s.Equals( "1" ) )
1332 {
1333 return true;
1334 }
1335 }
1336  
1337 throw new TclException( interp, "expected boolean value but got \"" + inString + "\"" );
1338 }
1339 internal static void setupPrecisionTrace( Interp interp )
1340 // Current interpreter.
1341 {
1342 try
1343 {
1344 interp.traceVar( "tcl_precision", new PrecTraceProc(), TCL.VarFlag.GLOBAL_ONLY | TCL.VarFlag.TRACE_WRITES | TCL.VarFlag.TRACE_READS | TCL.VarFlag.TRACE_UNSETS );
1345 }
1346 catch ( TclException e )
1347 {
1348 throw new TclRuntimeError( "unexpected TclException: " + e.Message, e );
1349 }
1350 }
1351 internal static string printDouble( double number )
1352 // The number to format into a string.
1353 {
1354 string s = FormatCmd.toString( number, precision, 10 ).Replace( "E", "e" );
1355 int length = s.Length;
1356 for ( int i = 0; i < length; i++ )
1357 {
1358 if ( ( s[i] == '.' ) || System.Char.IsLetter( s[i] ) )
1359 {
1360 return s;
1361 }
1362 }
1363 return string.Concat( s, ".0" );
1364 }
1365 internal static string tryGetSystemProperty( string propName, string defautlValue )
1366 // Default value.
1367 {
1368 try
1369 {
1370  
1371 // ATK return System_Renamed.getProperty(propName);
1372 return System.Environment.GetEnvironmentVariable( "os.name" );
1373 }
1374 catch ( System.Security.SecurityException e )
1375 {
1376 return defautlValue;
1377 }
1378 }
1379 static Util()
1380 {
1381 precision = DEFAULT_PRECISION;
1382 }
1383 } // end Util
1384  
1385 /*
1386 *----------------------------------------------------------------------
1387 *
1388 * PrecTraceProc.java --
1389 *
1390 * The PrecTraceProc class is used to implement variable traces for
1391 * the tcl_precision variable to control precision used when
1392 * converting floating-point values to strings.
1393 *
1394 *----------------------------------------------------------------------
1395 */
1396  
1397 sealed class PrecTraceProc : VarTrace
1398 {
1399  
1400 // Maximal precision supported by Tcl.
1401  
1402 internal const int TCL_MAX_PREC = 17;
1403  
1404 public void traceProc( Interp interp, string name1, string name2, TCL.VarFlag flags )
1405 {
1406 // If the variable is unset, then recreate the trace and restore
1407 // the default value of the format string.
1408  
1409 if ( ( flags & TCL.VarFlag.TRACE_UNSETS ) != 0 )
1410 {
1411 if ( ( ( flags & TCL.VarFlag.TRACE_DESTROYED ) != 0 ) && ( ( flags & TCL.VarFlag.INTERP_DESTROYED ) == 0 ) )
1412 {
1413 interp.traceVar( name1, name2, new PrecTraceProc(), TCL.VarFlag.GLOBAL_ONLY | TCL.VarFlag.TRACE_WRITES | TCL.VarFlag.TRACE_READS | TCL.VarFlag.TRACE_UNSETS );
1414 Util.precision = Util.DEFAULT_PRECISION;
1415 }
1416 return;
1417 }
1418  
1419 // When the variable is read, reset its value from our shared
1420 // value. This is needed in case the variable was modified in
1421 // some other interpreter so that this interpreter's value is
1422 // out of date.
1423  
1424 if ( ( flags & TCL.VarFlag.TRACE_READS ) != 0 )
1425 {
1426 interp.setVar( name1, name2, TclInteger.newInstance( Util.precision ), flags & TCL.VarFlag.GLOBAL_ONLY );
1427 return;
1428 }
1429  
1430 // The variable is being written. Check the new value and disallow
1431 // it if it isn't reasonable.
1432 //
1433 // (ToDo) Disallow it if this is a safe interpreter (we don't want
1434 // safe interpreters messing up the precision of other
1435 // interpreters).
1436  
1437 TclObject tobj = null;
1438 try
1439 {
1440 tobj = interp.getVar( name1, name2, ( flags & TCL.VarFlag.GLOBAL_ONLY ) );
1441 }
1442 catch ( TclException e )
1443 {
1444 // Do nothing when fixme does not exist.
1445 }
1446  
1447 string value;
1448  
1449 if ( tobj != null )
1450 {
1451  
1452 value = tobj.ToString();
1453 }
1454 else
1455 {
1456 value = "";
1457 }
1458  
1459 StrtoulResult r = Util.strtoul( value, 0, 10 );
1460  
1461 if ( ( r == null ) || ( r.value <= 0 ) || ( r.value > TCL_MAX_PREC ) || ( r.value > 100 ) || ( r.index == 0 ) || ( r.index != value.Length ) )
1462 {
1463 interp.setVar( name1, name2, TclInteger.newInstance( Util.precision ), TCL.VarFlag.GLOBAL_ONLY );
1464 throw new TclException( interp, "improper value for precision" );
1465 }
1466  
1467 Util.precision = (int)r.value;
1468 }
1469 } // end PrecTraceProc
1470 }