001: /*
002: * InterpCmd.java --
003: *
004: * Implements the built-in "interp" Tcl command.
005: *
006: * Copyright (c) 2000 Christian Krone.
007: *
008: * See the file "license.terms" for information on usage and
009: * redistribution of this file, and for a DISCLAIMER OF ALL
010: * WARRANTIES.
011: *
012: * RCS: @(#) $Id: InterpCmd.java,v 1.3 2006/01/26 19:49:18 mdejong Exp $
013: *
014: */
015:
016: package tcl.lang;
017:
018: import java.util.*;
019:
020: /**
021: * This class implements the built-in "interp" command in Tcl.
022: */
023:
024: class InterpCmd implements Command {
025:
026: static final private String options[] = { "alias", "aliases",
027: "create", "delete", "eval", "exists", "expose", "hide",
028: "hidden", "issafe", "invokehidden", "marktrusted",
029: "slaves", "share", "target", "transfer" };
030: static final private int OPT_ALIAS = 0;
031: static final private int OPT_ALIASES = 1;
032: static final private int OPT_CREATE = 2;
033: static final private int OPT_DELETE = 3;
034: static final private int OPT_EVAL = 4;
035: static final private int OPT_EXISTS = 5;
036: static final private int OPT_EXPOSE = 6;
037: static final private int OPT_HIDE = 7;
038: static final private int OPT_HIDDEN = 8;
039: static final private int OPT_ISSAFE = 9;
040: static final private int OPT_INVOKEHIDDEN = 10;
041: static final private int OPT_MARKTRUSTED = 11;
042: static final private int OPT_SLAVES = 12;
043: static final private int OPT_SHARE = 13;
044: static final private int OPT_TARGET = 14;
045: static final private int OPT_TRANSFER = 15;
046:
047: static final private String createOptions[] = { "-safe", "--" };
048: static final private int OPT_CREATE_SAFE = 0;
049: static final private int OPT_CREATE_LAST = 1;
050:
051: static final private String hiddenOptions[] = { "-global", "--" };
052: static final private int OPT_HIDDEN_GLOBAL = 0;
053: static final private int OPT_HIDDEN_LAST = 1;
054:
055: /**
056: *----------------------------------------------------------------------
057: *
058: * Tcl_InterpObjCmd -> cmdProc
059: *
060: * This procedure is invoked as part of the Command interface to
061: * process the "interp" Tcl command. See the user documentation
062: * for details on what it does.
063: *
064: * Results:
065: * None.
066: *
067: * Side effects:
068: * See the user documentation.
069: *
070: *----------------------------------------------------------------------
071: */
072:
073: public void cmdProc(Interp interp, // Current interpreter.
074: TclObject[] objv) // Argument list.
075: throws TclException // A standard Tcl exception.
076: {
077: if (objv.length < 2) {
078: throw new TclNumArgsException(interp, 1, objv,
079: "cmd ?arg ...?");
080: }
081: int cmd = TclIndex.get(interp, objv[1], options, "option", 0);
082:
083: switch (cmd) {
084: case OPT_ALIAS: {
085: if (objv.length >= 4) {
086: Interp slaveInterp = getInterp(interp, objv[2]);
087:
088: if (objv.length == 4) {
089: InterpAliasCmd.describe(interp, slaveInterp,
090: objv[3]);
091: return;
092: }
093: if ((objv.length == 5)
094: && ("".equals(objv[4].toString()))) {
095: InterpAliasCmd.delete(interp, slaveInterp, objv[3]);
096: return;
097: }
098: if (objv.length > 5) {
099: Interp masterInterp = getInterp(interp, objv[4]);
100: if ("".equals(objv[5].toString())) {
101: if (objv.length == 6) {
102: InterpAliasCmd.delete(interp, slaveInterp,
103: objv[3]);
104: return;
105: }
106: } else {
107: InterpAliasCmd
108: .create(interp, slaveInterp,
109: masterInterp, objv[3], objv[5],
110: 6, objv);
111: return;
112: }
113: }
114: }
115: throw new TclNumArgsException(interp, 2, objv,
116: "slavePath slaveCmd ?masterPath masterCmd? ?args ..?");
117: }
118: case OPT_ALIASES: {
119: Interp slaveInterp = getInterp(interp, objv);
120: InterpAliasCmd.list(interp, slaveInterp);
121: break;
122: }
123: case OPT_CREATE: {
124:
125: // Weird historical rules: "-safe" is accepted at the end, too.
126:
127: boolean safe = interp.isSafe;
128:
129: TclObject slaveNameObj = null;
130: boolean last = false;
131: for (int i = 2; i < objv.length; i++) {
132: if ((!last) && (objv[i].toString().charAt(0) == '-')) {
133: int index = TclIndex.get(interp, objv[i],
134: createOptions, "option", 0);
135: if (index == OPT_CREATE_SAFE) {
136: safe = true;
137: continue;
138: }
139: i++;
140: last = true;
141: }
142: if (slaveNameObj != null) {
143: throw new TclNumArgsException(interp, 2, objv,
144: "?-safe? ?--? ?path?");
145: }
146: slaveNameObj = objv[i];
147: }
148: if (slaveNameObj == null) {
149:
150: // Create an anonymous interpreter -- we choose its name and
151: // the name of the command. We check that the command name
152: // that we use for the interpreter does not collide with an
153: // existing command in the master interpreter.
154:
155: int i = 0;
156: while (interp.getCommand("interp" + i) != null) {
157: i++;
158: }
159: slaveNameObj = TclString.newInstance("interp" + i);
160: }
161: InterpSlaveCmd.create(interp, slaveNameObj, safe);
162: interp.setResult(slaveNameObj);
163: break;
164: }
165: case OPT_DELETE: {
166: for (int i = 2; i < objv.length; i++) {
167: Interp slaveInterp = getInterp(interp, objv[i]);
168:
169: if (slaveInterp == interp) {
170: throw new TclException(interp,
171: "cannot delete the current interpreter");
172: }
173: InterpSlaveCmd slave = slaveInterp.slave;
174: slave.masterInterp
175: .deleteCommandFromToken(slave.interpCmd);
176: }
177: break;
178: }
179: case OPT_EVAL: {
180: if (objv.length < 4) {
181: throw new TclNumArgsException(interp, 2, objv,
182: "path arg ?arg ...?");
183: }
184: Interp slaveInterp = getInterp(interp, objv[2]);
185: InterpSlaveCmd.eval(interp, slaveInterp, 3, objv);
186: break;
187: }
188: case OPT_EXISTS: {
189: boolean exists = true;
190:
191: try {
192: getInterp(interp, objv);
193: } catch (TclException e) {
194: if (objv.length > 3) {
195: throw e;
196: }
197: exists = false;
198: }
199: interp.setResult(exists);
200: break;
201: }
202: case OPT_EXPOSE: {
203: if (objv.length < 4 || objv.length > 5) {
204: throw new TclNumArgsException(interp, 2, objv,
205: "path hiddenCmdName ?cmdName?");
206: }
207: Interp slaveInterp = getInterp(interp, objv[2]);
208: InterpSlaveCmd.expose(interp, slaveInterp, 3, objv);
209: break;
210: }
211: case OPT_HIDE: {
212: if (objv.length < 4 || objv.length > 5) {
213: throw new TclNumArgsException(interp, 2, objv,
214: "path cmdName ?hiddenCmdName?");
215: }
216: Interp slaveInterp = getInterp(interp, objv[2]);
217: InterpSlaveCmd.hide(interp, slaveInterp, 3, objv);
218: break;
219: }
220: case OPT_HIDDEN: {
221: Interp slaveInterp = getInterp(interp, objv);
222: InterpSlaveCmd.hidden(interp, slaveInterp);
223: break;
224: }
225: case OPT_ISSAFE: {
226: Interp slaveInterp = getInterp(interp, objv);
227: interp.setResult(slaveInterp.isSafe);
228: break;
229: }
230: case OPT_INVOKEHIDDEN: {
231: boolean global = false;
232: int i;
233: for (i = 3; i < objv.length; i++) {
234: if (objv[i].toString().charAt(0) != '-') {
235: break;
236: }
237: int index = TclIndex.get(interp, objv[i],
238: hiddenOptions, "option", 0);
239: if (index == OPT_HIDDEN_GLOBAL) {
240: global = true;
241: } else {
242: i++;
243: break;
244: }
245: }
246: if (objv.length - i < 1) {
247: throw new TclNumArgsException(interp, 2, objv,
248: "path ?-global? ?--? cmd ?arg ..?");
249: }
250: Interp slaveInterp = getInterp(interp, objv[2]);
251: InterpSlaveCmd.invokeHidden(interp, slaveInterp, global, i,
252: objv);
253: break;
254: }
255: case OPT_MARKTRUSTED: {
256: if (objv.length != 3) {
257: throw new TclNumArgsException(interp, 2, objv, "path");
258: }
259: Interp slaveInterp = getInterp(interp, objv[2]);
260: InterpSlaveCmd.markTrusted(interp, slaveInterp);
261: break;
262: }
263: case OPT_SLAVES: {
264: Interp slaveInterp = getInterp(interp, objv);
265:
266: TclObject result = TclList.newInstance();
267: for (Iterator iter = slaveInterp.slaveTable.entrySet()
268: .iterator(); iter.hasNext();) {
269: Map.Entry entry = (Map.Entry) iter.next();
270: String string = (String) entry.getKey();
271: TclList.append(interp, result, TclString
272: .newInstance(string));
273: }
274: interp.setResult(result);
275:
276: break;
277: }
278: case OPT_SHARE: {
279: if (objv.length != 5) {
280: throw new TclNumArgsException(interp, 2, objv,
281: "srcPath channelId destPath");
282: }
283: Interp masterInterp = getInterp(interp, objv[2]);
284:
285: Channel chan = TclIO.getChannel(masterInterp, objv[3]
286: .toString());
287: if (chan == null) {
288: throw new TclException(interp,
289: "can not find channel named \""
290: + objv[3].toString() + "\"");
291: }
292:
293: Interp slaveInterp = getInterp(interp, objv[4]);
294: TclIO.registerChannel(slaveInterp, chan);
295: break;
296: }
297: case OPT_TARGET: {
298: if (objv.length != 4) {
299: throw new TclNumArgsException(interp, 2, objv,
300: "path alias");
301: }
302:
303: Interp slaveInterp = getInterp(interp, objv[2]);
304: String aliasName = objv[3].toString();
305: Interp targetInterp = InterpAliasCmd.getTargetInterp(
306: slaveInterp, aliasName);
307: if (targetInterp == null) {
308: throw new TclException(interp, "alias \"" + aliasName
309: + "\" in path \"" + objv[2].toString()
310: + "\" not found");
311: }
312: if (!getInterpPath(interp, targetInterp)) {
313: throw new TclException(interp,
314: "target interpreter for alias \"" + aliasName
315: + "\" in path \"" + objv[2].toString()
316: + "\" is not my descendant");
317: }
318: break;
319: }
320: case OPT_TRANSFER: {
321: if (objv.length != 5) {
322: throw new TclNumArgsException(interp, 2, objv,
323: "srcPath channelId destPath");
324: }
325: Interp masterInterp = getInterp(interp, objv[2]);
326:
327: Channel chan = TclIO.getChannel(masterInterp, objv[3]
328: .toString());
329: if (chan == null) {
330: throw new TclException(interp,
331: "can not find channel named \""
332: + objv[3].toString() + "\"");
333: }
334:
335: Interp slaveInterp = getInterp(interp, objv[4]);
336: TclIO.registerChannel(slaveInterp, chan);
337: TclIO.unregisterChannel(masterInterp, chan);
338: break;
339: }
340: }
341: }
342:
343: /*
344: *---------------------------------------------------------------------------
345: *
346: * GetInterp2 -> getInterp
347: *
348: * Helper function for Tcl_InterpObjCmd() to convert the interp name
349: * potentially specified on the command line to an Tcl_Interp.
350: *
351: * Results:
352: * The return value is the interp specified on the command line,
353: * or the interp argument itself if no interp was specified on the
354: * command line. If the interp could not be found or the wrong
355: * number of arguments was specified on the command line, the return
356: * value is NULL and an error message is left in the interp's result.
357: *
358: * Side effects:
359: * None.
360: *
361: *---------------------------------------------------------------------------
362: */
363:
364: private static Interp getInterp(Interp interp, // Default interp if no interp was specified
365: // on the command line.
366: TclObject[] objv) // Argument objects.
367: throws TclException {
368: if (objv.length == 2) {
369: return interp;
370: } else if (objv.length == 3) {
371: return getInterp(interp, objv[2]);
372: } else {
373: throw new TclNumArgsException(interp, 2, objv, "?path?");
374: }
375: }
376:
377: /**
378: *----------------------------------------------------------------------
379: *
380: * Tcl_GetInterpPath -> getInterpPath
381: *
382: * Sets the result of the asking interpreter to a proper Tcl list
383: * containing the names of interpreters between the asking and
384: * target interpreters. The target interpreter must be either the
385: * same as the asking interpreter or one of its slaves (including
386: * recursively).
387: *
388: * Results:
389: * true if the target interpreter is the same as, or a descendant
390: * of, the asking interpreter; false otherwise. This way one can
391: * distinguish between the case where the asking and target interps
392: * are the same (true is returned) and when the target is not a
393: * descendant of the asking interpreter (in which case false is returned).
394: *
395: * Side effects:
396: * None.
397: *
398: *----------------------------------------------------------------------
399: */
400:
401: private static boolean getInterpPath(Interp askingInterp, // Interpreter to start search from.
402: Interp targetInterp) // Interpreter to find.
403: throws TclException {
404: if (targetInterp == askingInterp) {
405: return true;
406: }
407: if (targetInterp == null || targetInterp.slave == null) {
408: return false;
409: }
410:
411: if (!getInterpPath(askingInterp,
412: targetInterp.slave.masterInterp)) {
413: return false;
414: }
415: askingInterp.appendElement(targetInterp.slave.path);
416: return true;
417: }
418:
419: /**
420: *----------------------------------------------------------------------
421: *
422: * getInterp --
423: *
424: * Helper function to find a slave interpreter given a pathname.
425: *
426: * Results:
427: * Returns the slave interpreter known by that name in the calling
428: * interpreter, or NULL if no interpreter known by that name exists.
429: *
430: * Side effects:
431: * Assigns to the pointer variable passed in, if not NULL.
432: *
433: *----------------------------------------------------------------------
434: */
435:
436: static Interp getInterp(Interp interp, // Interp. to start search from.
437: TclObject path) // List object containing name of interp. to
438: // be found.
439: throws TclException {
440: TclObject[] objv = TclList.getElements(interp, path);
441: Interp searchInterp = interp; //Interim storage for interp. to find.
442:
443: for (int i = 0; i < objv.length; i++) {
444: String name = objv[i].toString();
445: if (!searchInterp.slaveTable.containsKey(name)) {
446: searchInterp = null;
447: break;
448: }
449: InterpSlaveCmd slave = (InterpSlaveCmd) searchInterp.slaveTable
450: .get(name);
451: searchInterp = slave.slaveInterp;
452: if (searchInterp == null) {
453: break;
454: }
455: }
456:
457: if (searchInterp == null) {
458: throw new TclException(interp,
459: "could not find interpreter \"" + path.toString()
460: + "\"");
461: }
462:
463: return searchInterp;
464: }
465:
466: } // end InterpCmd
|