This patch should be applied to the
"ajuba-tclblend-contract-2000-08-01-branch".

The patch includes the following:

  - fix bugs in tcl.lang.Notifier
  - make TclBlend work with the Jacl shell
  - add mutex for multi thread TclBlend initialization
  - add (Win) makefile targets for testing TclBlend in JVM

This patch together with Mo's changes on removing the global lock and making
JNIEnv thread local make TclBlend almost thread safe.  I say "almost"
because we still need to make one last change to the Java side of TclBlend
to make the Notifier class per Interp.

I outlined the various initialization paths the TclBlend can go through and
how the mutex protects these situations in the following document, item 3
and 4.  Your comments and questions are welcome.

http://www-cs-students.stanford.edu/~jwu/blendchanges.txt

-- Jiang Wu
   [EMAIL PROTECTED]


Index: ChangeLog
===================================================================
RCS file: /cvsroot/tcljava/ChangeLog,v
retrieving revision 1.49.2.2
diff -b -u 
-r1.49.2.2 ChangeLog
--- ChangeLog  2000/07/30 07:17:08     1.49.2.2
+++ ChangeLog  
2000/08/05 23:25:45
@@ -1,3 +1,24 @@
+2000-08-03  Jiang Wu   <[EMAIL PROTECTED]>
+   
 * src/tclblend/tcl/lang/Notifier.java:
+        Fix the following Notifier bugs:
+    
     - infinite loop when doOneEvent is called recursively
+       - synchronization 
deadlock between serviceEvent and queueEvent
+        - deleteEvent() does not work 
properly
+       * src/tclblend/tcl/lang/Util.java:
+    * 
src/tclblend/tcl/lang/Interp.java:
+  Added the necessary methods for tcl.lang.Shell.
+       * src/native/javaCmd.c:
+       * src/native/javaInterp.c:
+    Added a global 
mutex to protect TclBlend initialization from
+  multiple C or Java threads.
+   * 
win/makefile.vc
+     Modified the Win makefile to build the Jacl Shell for tclblend.
+       Added a 'blendsh.install' target to install a 'blendsh.bat' that
+      can be 
used to start a Java shell running TclBlend.  Added a
+  'test_jvmblend.exec' target 
to run the TclBlend test suite using
+      JVM loading TclBlend.
+
+
 2000-07-30  Mo 
DeJong  <[EMAIL PROTECTED]>
 
       * src/native/java.h:
Index: src/native/javaCmd.c
===================================================================
RCS file: 
/cvsroot/tcljava/src/native/javaCmd.c,v
retrieving revision 1.9.2.1
diff -b -u 
-r1.9.2.1 javaCmd.c
--- javaCmd.c 2000/07/30 07:17:08     1.9.2.1
+++ javaCmd.c   
2000/08/05 23:25:48
@@ -94,6 +94,22 @@
 static int initialized_javaVM = 0;
 
 /*
+ * 
Declare a global mutex to protect the creation and initialization of the
+ * JVM from 
mutiple threads.  This mutex is used in conjunction with the
+ * 'initialized_javaVM' 
flag.  This mutex is used in javaCmd.c as well as
+ * javaInterp.c.
+ *
+ * FIXME: 
don't want to use the flag TCL_THREADS explicitly.  This may be
+ * better if in the 
future the same TclBlend binary can be made to work with
+ * both threaded and 
non-threaded Tcl libraries.  For now, we will use accessor
+ * functions 
lockJVMInitMutex() and unlockJVMInitMutex().
+ */
+TCL_DECLARE_MUTEX(javaVM_init_mutex)
+
+TCLBLEND_EXTERN void            
LockJVMInitMutex();
+TCLBLEND_EXTERN void            UnlockJVMInitMutex();
+
+/*
  * 
The following array contains the class names and jclass pointers for
  * all of the 
classes used by this module.  It is used to initialize
  * the java structure's jclass 
slots.
@@ -242,6 +258,13 @@
     fprintf(stderr, "Tcl Blend debug: CLASSPATH is 
\"%s\"\n", getenv("CLASSPATH"));
 #endif /* TCLBLEND_DEBUG */
 
+    /*
+     * 
Calling JavaGetEnv() and JavaSetupJava() should be atomic because these
+     * two 
functions may alter global data.  Lock the JVM init mutex to create
+     * a critical 
section.
+     */
+    LockJVMInitMutex();
+    
     env = JavaGetEnv(interp);
 
     
/*
@@ -254,6 +277,7 @@
     fprintf(stderr, "Tcl Blend debug: JVM init failed in 
javaCmd.c:\n");
 #endif /* TCLBLEND_DEBUG */
 
+        UnlockJVMInitMutex();
   
return TCL_ERROR;
     }
 
@@ -275,11 +299,18 @@
 
 
   if (JavaSetupJava(env, interp) 
!= TCL_OK) {
+       UnlockJVMInitMutex();
          return TCL_ERROR;
  }
     }
 
   
  /*
+     * End critical section. From this point on, the code is thread
+     * 
specific.
+     */
+    UnlockJVMInitMutex();
+    
+    /*
      * Allocate a new 
Interp instance to wrap this interpreter.
      */
 
@@ -405,7 +436,7 @@
     }
 
     
/* FIXME  : we need to put a mutex around this create JVM/attach step */
-
+    /* 
^^^^^ -- no need for mutex here, use mutex in the caller function */
 #ifdef 
TCLBLEND_DEBUG
     fprintf(stderr, "Tcl Blend debug: init 1.2 JVM in javaCmd.c\n");
 
#endif /* TCLBLEND_DEBUG */
@@ -573,7 +604,7 @@
     }
 
     /* FIXME: need to put a 
mutex around this create/attach step */
-
+    /* ^^^^^ -- no need for mutex here, use 
mutex in the caller function */
 #ifdef TCLBLEND_DEBUG
     fprintf(stderr, "Tcl Blend 
debug: init 1.1 JVM in javaCmd.c: \n");
 #endif /* TCLBLEND_DEBUG */
@@ -846,6 +877,7 
@@
 
 
     /* FIXME : we need to put a mutex around this test/set */
+    /* ^^^^^ -- 
no need for mutex here, use mutex in the caller function */
     if 
(initialized_javaVM) {
    return TCL_OK;
     }
@@ -1122,3 +1154,45 @@
     return 
buf;
 }
 
+
+/*
+ 
*----------------------------------------------------------------------
+ *
+ * 
LockJVMInitMutex --
+ *
+ * Acquire the 'init_javaVM_mutex'.
+ *
+ * Results:
+ *   
None.
+ *
+ * Side effects:
+ * Maybe block the caller until the mutex is available.
+ 
*
+ *----------------------------------------------------------------------
+ */
+TCLBLEND_EXTERN void
+LockJVMInitMutex()
+{
+    Tcl_MutexLock(&javaVM_init_mutex);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * UnlockJVMInitMutex --
+ *
+ *      Release the 'init_javaVM_mutex'.
+ *
+ * 
Results:
+ *      None.
+ *
+ * Side effects:
+ *      None.
+ *
+ 
*----------------------------------------------------------------------
+ */
+TCLBLEND_EXTERN void
+UnlockJVMInitMutex()
+{
+    
Tcl_MutexUnlock(&javaVM_init_mutex);
+}
Index: src/native/javaInterp.c
===================================================================
RCS file: 
/cvsroot/tcljava/src/native/javaInterp.c,v
retrieving revision 1.7.2.1
diff -b -u 
-r1.7.2.1 javaInterp.c
--- javaInterp.c  2000/07/30 07:17:09     1.7.2.1
+++ 
javaInterp.c        2000/08/05 23:25:51
@@ -28,6 +28,12 @@
 } JavaTraceInfo;
 
 /*
+ * 
This file wants to use lockJVMInitMutex() and unlockJVMInitMutex().
+ */
+TCLBLEND_EXTERN void            LockJVMInitMutex();
+TCLBLEND_EXTERN void            
UnlockJVMInitMutex();
+
+/*
  * Declaractions for functions used only in this file.
  
*/
 
@@ -102,6 +108,14 @@
     Tcl_Interp *interp;
 
     interp = Tcl_CreateInterp();
+
+    /*
+     * JavaSetupJava() should be executed atomically because it may
+     * 
alter global data.  Use the JVM init mutex to create a critical
+     * section.
+     
*/
+    LockJVMInitMutex();
+    
     if (JavaSetupJava(env, interp) != TCL_OK) {
    
    jclass err = (*env)->FindClass(env, "tcl/lang/TclRuntimeError");
       if (err) {
@@ -112,6 +126,11 @@
     } else {
  *(Tcl_Interp**)&lvalue = interp;
     }
+
+    /*
+     * End critical section.
+     */
+    UnlockJVMInitMutex();
     return lvalue;
 
}
 
Index: src/tclblend/tcl/lang/Interp.java
===================================================================
RCS file: 
/cvsroot/tcljava/src/tclblend/tcl/lang/Interp.java,v
retrieving revision 1.16
diff -b 
-u -r1.16 Interp.java
--- Interp.java        2000/07/30 02:37:18     1.16
+++ 
Interp.java    2000/08/05 23:25:53
@@ -318,6 +318,37 @@
 /*
  
*----------------------------------------------------------------------
  *
+ * setVar 
--
+ *
+ *        Set the value of a variable.
+ *
+ * Results:
+ *       Returns the 
new value of the variable.
+ *
+ * Side effects:
+ *        May trigger traces.
+ *
+ 
*----------------------------------------------------------------------
+ */
+
+public 
final TclObject
+setVar(
+    String name,             // Name of variable, array, or 
array element
+                          // to set.
+    String value,           // 
New value for variable.
+    int flags)                      // Various flags that 
tell how to set value:
+                          // any of GLOBAL_ONLY, 
NAMESPACE_ONLY,
+                                // APPEND_VALUE, LIST_ELEMENT, or
+   
                          // LEAVE_ERR_MSG. 
+throws
+    TclException
+{
+    return 
setVar(name, TclString.newInstance(value), flags);
+}
+
+/*
+ 
*----------------------------------------------------------------------
+ *
  * getVar 
--
  *
  *    Get the value of a variable.
@@ -819,8 +850,23 @@
 throws 
     
TclException    // A standard Tcl exception.
 {
+    // Append the script to the event 
list by calling "history add <script>".
+    // We call the eval method with the 
command of type TclObject, so that
+    // we don't have to deal with funny chars 
("{}[]$\) in the script.
+
+    try {
+       TclObject cmd = TclList.newInstance();
+ 
       TclList.append(this, cmd, TclString.newInstance("history"));
+  
TclList.append(this, cmd, TclString.newInstance("add"));
+      TclList.append(this, 
cmd, script);
+    eval(cmd, 0);
+    } catch (Exception e) {}
+
+    // Finally 
evaluate the script.
+
+    eval(script, flags);
+    
     // FIXME : need native 
implementation
-    throw new TclRuntimeError("Not implemented yet.");
 }
 
 /*
@@ 
-846,8 +892,11 @@
 throws 
     TclException
 {
+    // use the source command to 
evalFile
+    eval("source {" + s + "}", 0);
+
     // FIXME : need implementation
-   
 throw new TclRuntimeError("Not implemented yet.");
+    // throw new 
TclRuntimeError("Not implemented yet.");
 }
 
 /*
@@ -1031,6 +1080,42 @@
 public 
native void
 addErrorInfo(
     String message);          // Message to add to 
errorInfo
+
+/*
+ 
*----------------------------------------------------------------------
+ *
+ * 
updateReturnInfo --
+ *
+ *     This internal method is used by various parts of the 
Jacl
+ *   interpreter when a TclException of TCL.RETURN is received.
+ *
+ *      
This method is provided here for compatibility with Jacl Interp class
+ *       
methods.  This method should never be reached in TclBlend.
+ *
+ * Results:
+ * The 
return value is the true completion code to use for
+ *     the Tcl procedure, instead 
of TCL.RETURN. It's the same
+ *     value that was given to the "return -code" 
option.
+ *
+ *      If an internal value of TCL.OK is returned, it means than the
+ * 
      caller of this method should ignore any TclException that it has
+ *    just 
received and continue execution.
+ *
+ * Side effects:
+ * The errorInfo and errorCode 
variables may get modified.
+ *
+ 
*----------------------------------------------------------------------
+ */
+
+protected int
+updateReturnInfo()
+{
+    int code = TCL.ERROR;
+
+    
setErrorCode(TclInteger.newInstance(code));
+    addErrorInfo("Unexpected call to 
updateReturnInfo() in TclBlend.");
+    return code;
+}
 
 /*
  
*----------------------------------------------------------------------
Index: 
src/tclblend/tcl/lang/Notifier.java
===================================================================
RCS file: 
/cvsroot/tcljava/src/tclblend/tcl/lang/Notifier.java,v
retrieving revision 1.2
diff -b 
-u -r1.2 Notifier.java
--- Notifier.java        2000/01/25 03:42:25     1.2
+++ 
Notifier.java   2000/08/05 23:25:55
@@ -39,7 +39,7 @@
  * interpreter (thread).
  */
 
-public class Notifier {
+public class Notifier implements EventDeleter {
 
 private 
static Notifier globalNotifier;
 
@@ -65,6 +65,13 @@
 
 int refCount;
 
+// Mutex 
used to protect concurrent access to the internals of this Notifier
+// object.  For 
example, the queueing and dequeueing of objects from the
+// event list.
+
+private 
final Object notifierMutex = new Object();
+
+
 /*
  
*----------------------------------------------------------------------
  *
@@ -127,7 
+134,7 @@
  *
  *   Increment the reference count of the notifier. The notifier will
  
*    be kept in the notifierTable (and alive) as long as its reference
- *   count is 
greater than zero.
+ * count is greater than zero.  This method is concurrent safe.
  
*
  * Results:
  *       None.
@@ -138,13 +145,16 @@
  
*----------------------------------------------------------------------
  */
 
-public 
synchronized void
+public void
 preserve()
 {
+    synchronized (notifierMutex) {
     
if (refCount < 0) {
-       throw new TclRuntimeError("Attempting to preserve a freed 
Notifier");
+     throw new TclRuntimeError(
+                "Attempting to preserve 
a freed Notifier");
     }
     ++refCount;
+    }
 }
 
 /*
@@ -153,7 +163,8 @@
  * 
release --
  *
  * Decrement the reference count of the notifier. The notifier will
- 
*    be free when its refCount goes from one to zero.
+ *    be free when its refCount 
goes from one to zero.  This method is
+ *    concurrent safe.
  *
  * Results:
  *   
None.
@@ -165,9 +176,10 @@
  
*----------------------------------------------------------------------
  */
 
-public 
synchronized void
+public void
 release()
 {
+    synchronized (notifierMutex) {
     
if ((refCount == 0) && (primaryThread != null)) {
    throw new TclRuntimeError(
      
       "Attempting to release a Notifier before it's preserved");
@@ -181,6 +193,7 @@
 
        globalNotifier = null;
         dispose();
     }
+    }
 }
 
 /*
@@ -193,7 
+206,8 @@
  *      Events inserted before the marker will be processed in
  *      
first-in-first-out order, but before any events inserted at
  * the tail of the queue. 
 Events inserted at the head of the
- *  queue will be processed in last-in-first-out 
order.
+ * queue will be processed in last-in-first-out order.  This method is
+ * 
concurrent safe. 
  *
  * Results:
  *  None.
@@ -206,7 +220,7 @@
  
*----------------------------------------------------------------------
  */
 
-public 
synchronized void
+public void
 queueEvent(
     TclEvent evt,               // The 
event to put in the queue.
     int position)            // One of TCL.QUEUE_TAIL,
@@ 
-214,9 +228,9 @@
 {
     evt.notifier = this;
 
+    synchronized (notifierMutex) {
   
  if (position == TCL.QUEUE_TAIL) {
        // Append the event on the end of the 
queue.
-
         evt.next = null;
 
     if (firstEvent == null) {
@@ -227,7 +241,6 
@@
  lastEvent = evt;
     } else if (position == TCL.QUEUE_HEAD) {
         // Push 
the event on the head of the queue.
-
  evt.next = firstEvent;
         if (firstEvent 
== null) {
          lastEvent = evt;
@@ -236,7 +249,6 @@
     } else if (position == 
TCL.QUEUE_MARK) {
         // Insert the event after the current marker event and 
advance
         // the marker to the new event.
-
      if (markerEvent == null) {
   
      evt.next = firstEvent;
         firstEvent = evt;
@@ -250,10 +262,10 @@
    }
   
  } else {
        // Wrong flag.
-
       throw new TclRuntimeError("wrong position 
\"" + position +
            "\", must be TCL.QUEUE_HEAD, TCL.QUEUE_TAIL or 
TCL.QUEUE_MARK");
     }
+    }
 
     if (Thread.currentThread() != primaryThread) {
 
   alertNotifier();
@@ -267,7 +279,8 @@
  *
  *    Calls an EventDeleter for each 
event in the queue and deletes
  *       those for which deleter.deleteEvent() returns 
1. Events
- *     for which the deleter returns 0 are left in the queue.
+ *      for 
which the deleter returns 0 are left in the queue.   This 
+ *      method is 
concurrent safe. 
  *
  * Results:
  *        None.
@@ -278,13 +291,14 @@
  
*----------------------------------------------------------------------
  */
 
-public 
synchronized void
+public void
 deleteEvents(
     EventDeleter deleter)   // The 
deleter that checks whether an event
                            // should be removed.
 {
     TclEvent evt, prev;
 
+    synchronized (notifierMutex) {
     for (prev = 
null, evt = firstEvent; evt != null; evt = evt.next) {
         if 
(deleter.deleteEvent(evt) == 1) {
             if (firstEvent == evt) {
@@ -292,16 
+306,49 @@
                 if (evt.next == null) {
                     lastEvent = 
null;
                 }
+              if (markerEvent == evt) {
+                 
markerEvent = null;
+               }
             } else {
                 prev.next 
= evt.next;
+                if (evt.next == null) {
+                   lastEvent = 
prev;
             }
           if (markerEvent == evt) {
-         markerEvent = 
null;
+                   markerEvent = prev;
+               }
      }
         } 
else {
             prev = evt;
         }
     }
+    }
+}
+
+/*
+ 
*----------------------------------------------------------------------
+ *
+ * 
deleteEvent --
+ *
+ *    This method is required for this class being an 
EventDeleter.
+ *       Checks the given event to see if it is already processed.
+ *  
 This method together with 'deleteEvents' are used by serviceEvent to
+ *        
remove an event that is just processed in a concurrent safe manor.
+ *
+ * Results:
+ 
* Returns 1 if the given event is processed, 0 otherwise.
+ *
+ * Side effects:
+ *    
   None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+public int
+deleteEvent(
+    TclEvent evt) {               // Check whether 
this event should be removed.
+    return ((evt.isProcessing == true) &&
+         
(evt.isProcessed  == true)) ? 1 : 0;
 }
 
 /*
@@ -309,7 +356,8 @@
  *
  * 
serviceEvent --
  *
- *  Process one event from the event queue.
+ *     Process one 
event from the event queue.  This method is concurrent 
+ * safe and can be reentered 
recursively.
  *
  * Results:
  *     The return value is 1 if the procedure actually 
found an event
@@ -322,8 +370,7 @@
  *
  
*----------------------------------------------------------------------
  */
-
-synchronized int
+int
 serviceEvent(
     int flags)                   // Indicates 
what events should be processed.
                          // May be any combination 
of TCL.WINDOW_EVENTS
@@ -343,7 +390,8 @@
     // Loop through all the events in the 
queue until we find one
     // that can actually be handled.
 
-    for (evt = 
firstEvent; evt != null; evt = evt.next) {
+    evt = null;
+    while ((evt = 
getAvailableEvent(evt)) != null) {
        // Call the handler for the event.  If it 
actually handles the
         // event then free the storage for the event.  There are 
two
   // tricky things here, both stemming from the fact that the event
@@ -357,37 
+405,18 @@
        //    change almost arbitrarily while handling the event, so we
    
    //    can't depend on pointers found now still being valid when
        //    the 
handler returns.
-
+  synchronized (evt) {
   boolean b = evt.isProcessing;
  
evt.isProcessing = true;
 
     if ((b == false) && (evt.processEvent(flags) != 0)) {
 
     evt.isProcessed = true;
        if (evt.needsNotify) {
-            
synchronized(evt) {
                evt.notifyAll();
           }
-         }
-     if 
(firstEvent == evt) {
-          firstEvent = evt.next;
-                if (evt.next 
== null) {
-                   lastEvent = null;
-         }
-             if 
(markerEvent == evt) {
-                 markerEvent = null;
-               }
-       
  } else {
-          for (prev = firstEvent; prev.next != evt; prev = prev.next) {
-  
           // Empty loop body.
-               }
-             prev.next = evt.next;
- 
        if (evt.next == null) {
-                   lastEvent = prev;
-         }
-    
         if (markerEvent == evt) {
-                 markerEvent = prev;
-             
  }
-         }
+         
+              deleteEvents(this);     // this takes care 
of deletion of the
+                                 // just processed event
          
  return 1;
  } else {
           // The event wasn't actually handled, so we have to
@@ -395,19 +424,59 @@
      // attempted again.
 
          evt.isProcessing = b;
-    
 }
 
    // The handler for this event asked to defer it.  Just go on to
-       // 
the next event.
-
-  continue;
+             // the next event.  we will try to find 
another event to
+              // process when the while loop continues
+          }
+ }
     }
+
     return 0;
 }
 
 /*
  
*----------------------------------------------------------------------
  *
+ * 
getAvailableEvent --
+ *
+ *      Search through the internal event list to find the 
first event
+ *      that is has not being processed AND the event is not equal to the 
given
+ *     'skipEvent'.  This method is concurrent safe.
+ *       
+ * Results:
+ 
*       The return value is a pointer to the first found event that can be
+ *  
processed.  If no event is found, this method returns null.
+ *
+ * Side effects:
+ *  
 This method synchronizes on the 'notifierMutex', which will block any
+ *       other 
thread from adding or removing events from the event queue.
+ *
+ 
*----------------------------------------------------------------------
+ */
+    
+private TclEvent
+getAvailableEvent(
+    TclEvent    skipEvent)    // Indicates that 
the given event should not
+                          // be returned.  This argument 
can be null.
+{
+    TclEvent evt;
+    
+    synchronized(notifierMutex) {
+    for 
(evt = firstEvent ; evt != null ; evt = evt.next) {
+           if ((evt.isProcessing 
== false) &&
+                (evt.isProcessed  == false) &&
+                (evt != 
skipEvent)) {
+         return evt;
+       }
+ }
+    }
+    return null;
+}
+
+/*
+ 
*----------------------------------------------------------------------
+ *
  * 
doOneEvent --
  *
  *    Process a single event of some sort.  If there's no work to
@@ -503,7 +572,8 @@
  *
  * hasEvents --
  *
- *    Check to see if there are events 
waiting to be processed.
+ *   Check to see if there are events waiting to be 
processed.  This
+ *     method is concurrent safe.
  *
  * Results:
  * Returns true 
if there are events on the Notifier queue.
@@ -514,10 +584,12 @@
  
*----------------------------------------------------------------------
  */
 
-private final synchronized boolean
+private final boolean 
 hasEvents()
 {
-    
return (firstEvent != null);
+    boolean result = (getAvailableEvent(null) != null);
+
+    return result;
 }
 
 } // end Notifier
Index: src/tclblend/tcl/lang/Util.java
===================================================================
RCS file: 
/cvsroot/tcljava/src/tclblend/tcl/lang/Util.java,v
retrieving revision 1.1.1.1
diff -b 
-u -r1.1.1.1 Util.java
--- Util.java    1998/10/14 21:09:10     1.1.1.1
+++ Util.java  
 2000/08/05 23:25:55
@@ -59,6 +59,80 @@
 /*
  
*----------------------------------------------------------------------
  *
+ * isUnix 
--
+ *
+ *  Returns true if running on a Unix platform.
+ *
+ * Results:
+ *        
Returns a boolean.
+ *
+ * Side effects:
+ *     None.
+ *
+ 
*----------------------------------------------------------------------
+ */
+
+final 
static boolean 
+isUnix() {
+    if (isMac() || isWindows()) {
+     return false;
+   
 }
+    return true;
+}
+
+/*
+ 
*----------------------------------------------------------------------
+ *
+ * isMac 
--
+ *
+ *     Returns true if running on a Mac platform.
+ *
+ * Results:
+ * Returns 
a boolean.
+ *
+ * Side effects:
+ *     None.
+ *
+ 
*----------------------------------------------------------------------
+ */
+
+final 
static boolean 
+isMac() {
+    String os = System.getProperty("os.name");
+    if 
(os.toLowerCase().startsWith("mac")) {
+  return true;
+    }
+    return false;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 
isWindows --
+ *
+ * Returns true if running on a Windows platform.
+ *
+ * Results:
+ 
*     Returns a boolean.
+ *
+ * Side effects:
+ *     None.
+ *
+ 
*----------------------------------------------------------------------
+ */
+
+final 
static boolean 
+isWindows() {
+    String os = System.getProperty("os.name");
+    if 
(os.toLowerCase().startsWith("win")) {
+      return true;
+    }
+    return false;
+}
+
+/*
+ *----------------------------------------------------------------------
+ 
*
  * printDouble --
  *
  *       Returns the string form of a double. The exact 
formatting
Index: win/makefile.vc
===================================================================
RCS file: 
/cvsroot/tcljava/win/makefile.vc,v
retrieving revision 1.27.2.1
diff -b -u -r1.27.2.1 
makefile.vc
--- makefile.vc        2000/07/30 04:33:15     1.27.2.1
+++ makefile.vc    
    2000/08/05 23:26:00
@@ -350,6 +350,22 @@
               exit
 <<
 
+test_jvmblend.exec: test_tclblend.check
+   cd $(BUILD_DIR)
+        set 
CLASSPATH=$(TEST_CLASSPATH)
+        set 
PATH=$(TCL_DIR)\bin;$(BUILD_DIR);$(JAVA_RUNTIME_LIBS);$(PATH)
+   set 
TCL_LIBRARY=$(TCL_DIR)\lib\tcl8.3
+ $(JAVA) $(JAVA_FLAGS) \
+               
-DBUILD_DIR=$(BUILD_DIR) -DJAVA=$(JAVA) tcl.lang.Shell <<
+                set 
auto_path [concat [pwd] [set auto_path]]
+                cd {$(TOP_DIR)\tests}
+      
          puts "pwd is [pwd]"
+                puts "CLASSPATH is [set 
env(CLASSPATH)]"
+                puts "auto_path is [set auto_path]"
+                
source all
+                puts "Tests done."
+                exit
+<<
 
 
#----------------------------------------------------------------------
 # Running the 
Jacl test suite
@@ -567,7 +583,8 @@
     cd $(TCLBLEND_SRC_DIR)
         set 
CLASSPATH=$(TCLBLEND_CLASSPATH)
    $(JAVAC) $(JAVAC_FLAGS) \
-             -d 
$(TCLBLEND_BUILD_DIR) tcl\lang\*.java
+              -d $(TCLBLEND_BUILD_DIR) 
tcl\lang\*.java \
+            $(JACL_SRC_DIR)\tcl\lang\Shell.java
 
 tclblend.jar: 
tclblend.build
    cd $(TCLBLEND_BUILD_DIR)
@@ -601,6 +618,19 @@
  -@mkdir 
$(TCL_DIR)\lib\xputils
         -@$(COPYDIR) $(BUILD_DIR)\xputils 
$(TCL_DIR)\lib\xputils
 
+#
+# temp target for installing a blendsh.bat
+#
+blendsh.install:
+        -@echo Installing blendsh.bat in $(BIN_INSTALL_DIR)
+   
-@del $(BIN_INSTALL_DIR)\blendsh.bat
+  -@echo REM >> $(BIN_INSTALL_DIR)\blendsh.bat
+ 
 -@echo REM This batch file starts the Jacl/TclBlend shell with a JVM >> 
$(BIN_INSTALL_DIR)\blendsh.bat
+        -@echo REM >> $(BIN_INSTALL_DIR)\blendsh.bat
+ 
 -@echo set TCL_LIBRARY=$(TCL_DIR)\lib\tcl8.3>> $(BIN_INSTALL_DIR)\blendsh.bat
+ 
-@echo set PATH=$(BIN_INSTALL_DIR);$(LIB_INSTALL_DIR);$(JAVA_RUNTIME_LIBS) >> 
$(BIN_INSTALL_DIR)\blendsh.bat
+  -@echo set 
CLASSPATH=$(JAVA_CLASSPATH);$(LIB_INSTALL_DIR)\tclblend.jar;$(LIB_INSTALL_DIR)\tcljava.jar
 >> $(BIN_INSTALL_DIR)\blendsh.bat
+       -@echo $(JAVA) -cp %CLASSPATH% 
tcl.lang.Shell >> $(BIN_INSTALL_DIR)\blendsh.bat
 
 #
 # Check to make sure tclblend 
is built
@@ -639,6 +669,7 @@
       tcl.lang.Notifier \
    tcl.lang.TclList \
     
tcl.lang.TimerHandler \
+       tcl.lang.Shell \
       tcl.lang.Util
 
 

Reply via email to