wasCSharpSQLite – Rev 1

Subversion Repositories:
Rev:
/*
* BgErrorMgr --
*
*       This class manages the background errors for a Tcl interpreter.
*
* Copyright (c) 1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and
* redistribution of this file, and for a DISCLAIMER OF ALL
* WARRANTIES.
* 
* Included in SQLite3 port to C# for use in testharness only;  2008 Noah B Hart
*
* RCS @(#) $Id: BgErrorMgr.java,v 1.6 2002/01/21 06:34:26 mdejong Exp $
*
*/
using System;
using System.Collections;
using System.IO;

namespace tcl.lang
{

  /*
  * This class manages the background errors for a Tcl interpreter. It
  * stores the error information about the interpreter and use an idle
  * handler to report the error when the notifier is idle.
  */

  class BgErrorMgr : AssocData
  {
    private void InitBlock()
    {
      errors = new ArrayList( 10 );
    }

    /*
    * We manage the background errors in this interp instance.
    */

    internal Interp interp;

    /*
    * A TclObject for invoking the "bgerror" command. We use a TclObject
    * instead of a String so that we don't need to look up the command
    * every time.
    */

    internal TclObject bgerrorCmdObj;

    /*
    * A list of the pending background error handlers.
    */

    internal ArrayList errors;

    internal BgErrorMgr( Interp i )
    {
      InitBlock();
      interp = i;
      bgerrorCmdObj = TclString.newInstance( "bgerror" );
      bgerrorCmdObj.preserve();

      errors = new ArrayList( 10 );
    }
    internal void addBgError()
    {
      BgError bgErr = new BgError( this, interp.getNotifier() );

      // The addErrorInfo() call below (with an empty string)
      // ensures that errorInfo gets properly set.  It's needed in
      // cases where the error came from a utility procedure like
      // Interp.getVar() instead of Interp.eval(); in these cases
      // errorInfo still won't have been set when this procedure is
      // called.

      interp.addErrorInfo( "" );

      bgErr.errorMsg = interp.getResult();
      bgErr.errorInfo = null;
      try
      {
        bgErr.errorInfo = interp.getVar( "errorInfo", null, TCL.VarFlag.GLOBAL_ONLY );
      }
      catch ( TclException e )
      {
        // Do nothing if var does not exist.
      }

      bgErr.errorCode = null;
      try
      {
        bgErr.errorCode = interp.getVar( "errorCode", null, TCL.VarFlag.GLOBAL_ONLY );
      }
      catch ( TclException e )
      {
        // Do nothing if var does not exist.
      }

      bgErr.errorMsg.preserve();
      bgErr.errorInfo.preserve();
      bgErr.errorCode.preserve();

      errors.Add( bgErr );
    }
    public void disposeAssocData( Interp interp )
    // The interpreter in which this AssocData
    // instance is registered in.
    {
      for ( int i = errors.Count - 1; i >= 0; i-- )
      {
        BgError bgErr = (BgError)errors[i];
        errors.RemoveAt( i );
        bgErr.cancel();

        bgErr.errorMsg.release();
        bgErr.errorMsg = null;
        bgErr.errorInfo.release();
        bgErr.errorInfo = null;
        bgErr.errorCode.release();
        bgErr.errorCode = null;
      }

      bgerrorCmdObj.release();
      bgerrorCmdObj = null;
    }
    internal class BgError : IdleHandler
    {
      private void InitBlock( BgErrorMgr enclosingInstance )
      {
        this.enclosingInstance = enclosingInstance;
      }
      private BgErrorMgr enclosingInstance;
      public BgErrorMgr Enclosing_Instance
      {
        get
        {
          return enclosingInstance;
        }

      }

      /*
      * The interp's result, errorCode and errorInfo when the bgerror happened.
      */

      internal TclObject errorMsg;
      internal TclObject errorCode;
      internal TclObject errorInfo;

      internal BgError( BgErrorMgr enclosingInstance, Notifier n )
        : base( n )
      {
        InitBlock( enclosingInstance );
      }
      public override void processIdleEvent()
      {

        // During the execution of this method, elements may be removed from
        // the errors list (because a TCL.CompletionCode.BREAK was returned by the bgerror
        // command, or because the interp was deleted). We remove this
        // BgError instance from the list first so that this instance won't
        // be deleted twice.

        SupportClass.VectorRemoveElement( Enclosing_Instance.errors, this );

        // Restore important state variables to what they were at
        // the time the error occurred.

        try
        {
          Enclosing_Instance.interp.setVar( "errorInfo", null, errorInfo, TCL.VarFlag.GLOBAL_ONLY );
        }
        catch ( TclException e )
        {

          // Ignore any TclException's, possibly caused by variable traces on
          // the errorInfo variable. This is compatible with the behavior of
          // the Tcl C API.
        }

        try
        {
          Enclosing_Instance.interp.setVar( "errorCode", null, errorCode, TCL.VarFlag.GLOBAL_ONLY );
        }
        catch ( TclException e )
        {

          // Ignore any TclException's, possibly caused by variable traces on
          // the errorCode variable. This is compatible with the behavior of
          // the Tcl C API.
        }

        // Make sure, that the interpreter will surive the invocation
        // of the bgerror command.

        Enclosing_Instance.interp.preserve();

        try
        {

          // Invoke the bgerror command.

          TclObject[] argv = new TclObject[2];
          argv[0] = Enclosing_Instance.bgerrorCmdObj;
          argv[1] = errorMsg;

          Parser.evalObjv( Enclosing_Instance.interp, argv, 0, TCL.EVAL_GLOBAL );
        }
        catch ( TclException e )
        {
          switch ( e.getCompletionCode() )
          {

            case TCL.CompletionCode.ERROR:
              try
              {
                Channel chan = TclIO.getStdChannel( StdChannel.STDERR );

                if ( Enclosing_Instance.interp.getResult().ToString().Equals( "\"bgerror\" is an invalid command name or ambiguous abbreviation" ) )
                {
                  chan.write( Enclosing_Instance.interp, errorInfo );
                  chan.write( Enclosing_Instance.interp, "\n" );
                }
                else
                {
                  chan.write( Enclosing_Instance.interp, "bgerror failed to handle background error.\n" );
                  chan.write( Enclosing_Instance.interp, "    Original error: " );
                  chan.write( Enclosing_Instance.interp, errorMsg );
                  chan.write( Enclosing_Instance.interp, "\n" );
                  chan.write( Enclosing_Instance.interp, "    Error in bgerror: " );
                  chan.write( Enclosing_Instance.interp, Enclosing_Instance.interp.getResult() );
                  chan.write( Enclosing_Instance.interp, "\n" );
                }
                chan.flush( Enclosing_Instance.interp );
              }
              catch ( TclException e1 )
              {

                // Ignore.
              }
              catch ( IOException e2 )
              {

                // Ignore, too.
              }
              break;


            case TCL.CompletionCode.BREAK:

              for ( int i = Enclosing_Instance.errors.Count - 1; i >= 0; i-- )
              {
                BgError bgErr = (BgError)Enclosing_Instance.errors[i];
                Enclosing_Instance.errors.RemoveAt( i );
                bgErr.cancel();

                bgErr.errorMsg.release();
                bgErr.errorMsg = null;
                bgErr.errorInfo.release();
                bgErr.errorInfo = null;
                bgErr.errorCode.release();
                bgErr.errorCode = null;
              }
              break;
          }
        }

        Enclosing_Instance.interp.release();

        errorMsg.release();
        errorMsg = null;
        errorInfo.release();
        errorInfo = null;
        errorCode.release();
        errorCode = null;
      }
    } // end BgErrorMgr.BgError
  } // end BgErrorMgr
}