PageRenderTime 52ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/TCL/src/base/Util.cs

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