Jacl.java |
1 /* 2 * Jacl.java 3 * 4 * Copyright (c) 1998-2005, The University of Sheffield. 5 * 6 * This file is part of GATE (see http://gate.ac.uk/), and is free 7 * software, licenced under the GNU Library General Public License, 8 * Version 2, June 1991 (in the distribution as file licence.html, 9 * and also available at http://gate.ac.uk/gate/licence.html). 10 * 11 * Hamish Cunningham, 14/03/00 12 * 13 * $Id: Jacl.java,v 1.11 2005/01/11 13:51:37 ian Exp $ 14 */ 15 16 17 package gate.util; 18 19 import java.util.*; 20 21 import tcl.lang.*; 22 23 24 /** 25 * This class provides access to the Jacl Tcl interpreter, and 26 * caters for loading any Tcl scripts that live in the GATE source. 27 * It also serves as examples of how Tcl can be used from Java using 28 * the Jacl library (which is my excuse for those cases where there was 29 * an obvious easier way!). 30 * <P> 31 * Note that all GATE Tcl scripts should be in the namespace "GATE". 32 */ 33 public class Jacl 34 { 35 /** Debug flag */ 36 private static final boolean DEBUG = false; 37 38 /** The Tcl interpreter */ 39 private Interp interp; 40 41 /** Construction */ 42 public Jacl() { interp = new Interp(); } 43 44 /** Get the interpreter */ 45 public Interp getInterp() { return interp; } 46 47 /** Local fashion for newlines */ 48 private String nl = Strings.getNl(); 49 50 /** Some Tcl code to get us into the gate/src directory (from gate 51 * or a subdir). 52 */ 53 String goToGateSrcScript = 54 "set WD [pwd] "+nl+ 55 "if { ! [string match \"*gate*\" $WD] } { "+nl+ 56 " error \"not in the gate directories\" "+nl+ 57 "} "+nl+ 58 "while { [file tail $WD] != \"gate\" } { cd ..; set WD [pwd] } "+nl+ 59 "cd src "+nl; 60 61 /** Some Tcl code to find all the .tcl files under a directory. */ 62 private String findTclScript = 63 "set tclFiles [list] "+nl+ 64 " "+nl+ 65 "proc filter { dir } { "+nl+ 66 " global tclFiles "+nl+ 67 " "+nl+ 68 " foreach f [glob -nocomplain ${dir}/*] { "+nl+ 69 " if [file isdirectory $f] { filter $f } "+nl+ 70 " if [string match {*.tcl} $f] { "+nl+ 71 " lappend tclFiles [string range $f 2 end] "+nl+ 72 " } "+nl+ 73 " } "+nl+ 74 "} "+nl+ 75 " "+nl+ 76 "filter {.} ;# do the search "+nl+ 77 "return $tclFiles ;# return the result to the interpreter "+nl; 78 79 /** Locate any files named .tcl in the directory hierarchy under . 80 * and return a list of them. 81 */ 82 public List findScripts() throws TclException { 83 return findScripts(""); 84 } // findScripts() 85 86 /** Locate any files named .tcl in the directory hierarchy under . 87 * and return a list of them. The prelimScript parameter should be 88 * a non-null string containing Tcl code that will be evaluated before 89 * the finder script runs (so it can be used to change directory, 90 * for e.g.). 91 */ 92 public List findScripts(String prelimScript) throws TclException { 93 List scriptPaths = new ArrayList(); 94 95 String finderScript = prelimScript + findTclScript; 96 97 // "return" in a script evaluated from Java works by throwing an 98 // exception with completion code of TCL.RETURN (so using "set" to 99 // return a value is easier where possible) 100 try { 101 interp.eval(finderScript); 102 } catch(TclException e) { 103 if(e.getCompletionCode() != TCL.RETURN) // wasn't a "return" exception 104 throw(e); 105 } 106 107 TclObject resultObject = interp.getResult(); 108 TclObject pathsArray[] = TclList.getElements(interp, resultObject); 109 for(int i = 0; i < pathsArray.length; i++) 110 scriptPaths.add(pathsArray[i].toString()); 111 112 return scriptPaths; 113 } // findScripts 114 115 /** Copy scripts from the GATE source tree into the classes dir, so 116 * that they will make it into gate.jar, and so that getResource 117 * (used by Interp.evalResource) will find them. 118 */ 119 void copyGateScripts(List scriptPaths) throws TclException { 120 // tcl code to do the copy (move to GATE src dir first) 121 String copyScript = goToGateSrcScript + 122 "foreach f $scriptFilesToCopy { "+nl+ 123 " file copy -force $f ../classes/$f "+nl+ 124 "} "+nl; 125 126 // set a variable containing the list of paths to the scripts 127 TclObject tclPathsList = TclList.newInstance(); 128 ListIterator iter = scriptPaths.listIterator(); 129 while(iter.hasNext()) { 130 TclObject path = TclString.newInstance((String) iter.next()); 131 TclList.append(interp, tclPathsList, path); 132 } 133 interp.setVar("scriptFilesToCopy", tclPathsList, TCL.GLOBAL_ONLY); 134 135 // evaluate the copy script 136 interp.eval(copyScript); 137 } // copyGateScripts 138 139 /** Load a list of Tcl scripts. The class loader is used to find the 140 * scripts, so they must be on the class path, preferably in the same 141 * code base as this class. Naming: each path in the list should be 142 * the path to the script relative to the CLASSPATH. So, for e.g., if 143 * you have MyJar.jar on the classpath, and it contains a script housed 144 * in package x.y called z.tcl, the name should be x/y/z.tcl. (The class 145 * loader can then be asked to retrieve /x/y/z.tcl and will find the 146 * file in the jar.) 147 */ 148 public void loadScripts(List scriptPaths) throws TclException { 149 ListIterator iter = scriptPaths.listIterator(); 150 while(iter.hasNext()) { 151 String path = (String) iter.next(); 152 String leadingSlash = ""; 153 154 // leading "/" on path needed by classloader 155 if(! path.startsWith("/")) 156 leadingSlash = "/"; 157 interp.evalResource(leadingSlash + path); 158 } 159 } // loadScripts(scriptPaths) 160 161 /** Loads all the scripts in the GATE source. So to get a Tcl interpreter 162 * that's fully initialised with all the GATE Tcl code do: 163 * <PRE> 164 * Jacl jacl = new Jacl(); 165 * jacl.loadScripts(); 166 * </PRE> 167 */ 168 public void loadScripts() throws TclException { 169 listGateScripts(); 170 loadScripts(gateScriptsList); 171 } // loadScripts() 172 173 /** Set up the gateScriptsList member. This uses the ScriptsList.tcl 174 * script, which is built by "make tcl". 175 */ 176 void listGateScripts() throws TclException { 177 gateScriptsList = new ArrayList(); 178 179 interp.evalResource("/gate/util/ScriptsList.tcl"); 180 TclObject scriptsList = interp.getResult(); 181 182 TclObject pathsArray[] = TclList.getElements(interp, scriptsList); 183 for(int i = 0; i < pathsArray.length; i++) 184 gateScriptsList.add(pathsArray[i].toString()); 185 } // listGateScripts 186 187 /** This is a list of all the .tcl files in the GATE source, used by 188 * the loadScripts() method. 189 */ 190 private List gateScriptsList; 191 192 } // class Jacl 193 194 195 196 197 198 199