//============================================================================== // Interp.java //============================================================================== package tribble.net.ftp.shell; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.io.PrintWriter; import java.lang.Exception; import java.lang.IllegalArgumentException; import java.lang.Integer; import java.lang.Long; import java.lang.NumberFormatException; import java.lang.Process; import java.lang.Runtime; import java.lang.String; import java.lang.System; import java.lang.Thread; import java.util.ArrayList; import java.util.Date; import java.util.Random; import tribble.util.FilenamePattern; import tribble.util.RuntimeExec; import tribble.net.ftp.FTPClientAdapter; import tribble.net.ftp.FTPClient; import tribble.net.ftp.FTPException; /******************************************************************************* * FTP command script interpreter. * * *
*
Source code:
*
Available at: * http://david.tribble.com/src/java/tribble/net/ftp/shell/Interp.java *
*
Documentation:
*
Available at: * http://david.tribble.com/docs/tribble/net/ftp/shell/Interp.html *
*
* * * @version API 1.1 $Revision: 1.55 $ $Date: 2010/07/12 23:40:23 $ * @since API 1.0, 2007-03-15 * @author David R. Tribble (david@tribble.com). *

* Copyright ©2007-2010 by David R. Tribble, all rights reserved.
* Permission is granted to any person or entity except those designated by * by the United States Department of State as a terrorist, or terrorist * government or agency, to use and distribute this source code provided * that the original copyright notice remains present and unaltered. * * @see FTPCommandInterpreter * @see CommandParser * @see ExecFrame * @see BlockDef */ class Interp implements CommandCodes, VarNames { /** Revision information. */ static final String REV = "@(#)tribble/net/ftp/shell/Interp.java API 1.1 $Revision: 1.55 $ $Date: 2010/07/12 23:40:23 $\n"; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Constants /** Local native JVM newline character sequence. */ static final String LOCAL_NL = System.getProperty("line.separator"); /** Local native directory pathname separator. */ static final String SYS_DIRSEP = System.getProperty("file.separator"); /** Local current directory. */ static final String SYS_CURDIR = System.getProperty("user.dir"); /** Maximum number of simutaneous FTP sessions. */ private static final int MAX_SESSIONS = 100; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Variables /** Runtime environment. */ private Runtime m_runtime = Runtime.getRuntime(); /** Output stream. */ private PrintWriter m_out; /** Output stream. */ private PrintStream m_outS; /** Error output stream. */ private PrintStream m_errS; /** FTP session. */ private FTPClientAdapter[] m_sess = new FTPClientAdapter[MAX_SESSIONS]; /** Block definition for the entire command script. */ private BlockDef m_script; /** Commands (statements) to execute. */ private CommandNode m_cmds; /** Execution frame stack. */ private ExecFrame m_frame; /** Filename pattern matcher. */ private FilenamePattern m_matcher = new FilenamePattern("*", true); /** Var name buffer. */ private char[] m_vbuf = new char[80]; /** Source filename. */ private String m_fname = "-"; /** Local directory name. */ File m_localDir = new File(SYS_CURDIR); /** Execution start time. */ long m_startTime; /** Current date/time (as msec since 1970-01-01 00:00:00Z). */ long m_time; /** Commands (statements) executed. */ long m_nExecs; /** Pseudo-random number generator. */ Random m_rand = new Random(); /** Execution interrupt/stop flag. */ volatile boolean m_stop; /** Exit command flag. */ boolean m_exit; /** Generate verbose command tracing output (global setting). */ boolean m_verbose; /** Generate verbose command tracing output (current setting). */ boolean m_isVerbose; /** Limit the number of commands executed (to 1,000). */ boolean m_limitCmds; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Constructors /*************************************************************************** * Constructor. * * @param cmds * Parsed commands (statements) from a source command script. * * @param out * Output stream. * * @param err * Error output stream. * * @throws IllegalArgumentException (unchecked) * Thrown if cmds is malformed. * * @since 1.45, 2007-05-19 (1.1, 2007-03-16) */ Interp(CommandNode cmds, PrintStream out, PrintStream err) throws IllegalArgumentException { // Initialize // Set up if (cmds.m_cmd != CMD_BLOCK) throw new IllegalArgumentException( "Command must be a file block statement"); m_script = (BlockDef) cmds.m_args[0]; m_cmds = (CommandNode) cmds.m_args[1]; m_outS = out; m_out = new PrintWriter(m_outS, true); m_errS = err; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Command execution methods /*************************************************************************** * Stop this currently running FTP command script interpreter. * This sets an internal flag, which is checked before the next command is * executed, and every 3 seconds while the 'sleep' command is executing. * * @since 1.37, 2007-05-05 */ void stop() { // Signal for command executions to stop m_stop = true; // Signal all sessions to stop executing for (int i = 1; i < m_sess.length+1; i++) { FTPClientAdapter sess; sess = m_sess[i-1]; if (sess != null && sess.isConnected()) sess.stop(); } } /*************************************************************************** * Execute (interpret) the command script. * * @return * The final exit value of the script. * * @since 1.1, 2007-03-16 */ int execute() { int rc = 0; // Set up m_stop = false; m_isVerbose = m_verbose; if (m_isVerbose) m_out.println("> execute"); m_startTime = (new Date()).getTime(); m_time = m_startTime; m_rand.setSeed(0); m_nExecs = 0; m_exit = false; m_frame = new ExecFrame(m_script, m_cmds, null); m_sess[0] = new FTPClient(); defGlobalVar(VAR_COMMANDCNT, VAL_ZERO); defGlobalVar(VAR_ERROR, VAL_ZERO); defGlobalVar(VAR_ERRORCMD, VAL_EMPTY); defGlobalVar(VAR_ERRORCNT, VAL_ZERO); defGlobalVar(VAR_ERRORMSG, VAL_EMPTY); defGlobalVar(VAR_FILENAME, 's' + m_fname); defGlobalVar(VAR_HOST, VAL_EMPTY); defGlobalVar(VAR_LOCALDIR, 's' + SYS_CURDIR); defGlobalVar(VAR_PASSWORD, VAL_EMPTY); defGlobalVar(VAR_PORT, VAL_EMPTY); defGlobalVar(VAR_RANDOM, VAL_ZERO); defGlobalVar(VAR_REMOTEDIR, "s/"); defGlobalVar(VAR_TIME, "n" + m_time); defGlobalVar(VAR_USER, VAL_EMPTY); defGlobalVar(VAR_FILE, VAL_EMPTY); defGlobalVar(VAR_FILE_DIR, VAL_EMPTY); defGlobalVar(VAR_FILE_DIRSEP, 's' + SYS_DIRSEP); defGlobalVar(VAR_FILE_EXT, VAL_EMPTY); defGlobalVar(VAR_FILE_FILE, VAL_EMPTY); defGlobalVar(VAR_FILE_GROUP, VAL_EMPTY); defGlobalVar(VAR_FILE_HOST, VAL_EMPTY); defGlobalVar(VAR_FILE_NAME, VAL_EMPTY); defGlobalVar(VAR_FILE_OWNER, VAL_EMPTY); defGlobalVar(VAR_FILE_PATH, VAL_EMPTY); defGlobalVar(VAR_FILE_PERMS, VAL_EMPTY); defGlobalVar(VAR_FILE_SIZE, VAL_ZERO); defGlobalVar(VAR_FILE_TYPE, VAL_EMPTY); // Execute the commands in the script while (m_frame != null) { CommandNode cmd; // Check for an external interrupt if (m_stop) { m_out.println(); m_out.println("*** INTERRUPT (" + m_nExecs + " commands)"); m_out.flush(); break; } // Execute the next command node in the current frame cmd = m_frame.m_pc; if (cmd != null) { // Execute a command (statement) m_nExecs++; setGlobalNumVar(VAR_COMMANDCNT, m_nExecs); if (m_nExecs >= 1000 && m_limitCmds) { m_out.println(); m_out.println("*** TERMINATED (" + m_nExecs + " commands)"); m_out.flush(); break; } m_frame.m_pc = cmd.m_next; executeCmd(cmd); } else if (m_frame.m_scope.m_type != CMD_BLOCK) { // Start the next iteration of the loop block execALoopEnd(); } else { String s; // Get the last error value set in the frame s = m_frame.findVar(VAR_ERROR, null); rc = (int) cvtToInt(s); // Handle an 'exit' command if (m_exit) break; // Pop the execution frame from the stack m_frame = m_frame.pop(); } } // End of command script execution for (int i = 1; i < m_sess.length+1; i++) { if (m_sess[i-1] != null && m_sess[i-1].isConnected()) { if (m_isVerbose) m_out.println("> close &" + i); m_sess[i-1].disconnect(); } m_sess[i-1] = null; } m_time = (new Date()).getTime(); if (m_isVerbose) { long msec; String t; msec = m_time - m_startTime; t = (msec%1000) + ""; while (t.length() < 3) t = "0" + t; m_out.println("> exit " + rc + ", " + (msec/1000) + "." + t + " sec"); } // Return the final "$Error" value return rc; } /*************************************************************************** * Execute (interpret) a command node. * * @param cmd * Command to execute. * * @return * The next command (statement) to execute, or null if there are no more * commands to execute in the current execution frame. * * @since 1.1, 2007-03-16 */ private void executeCmd(CommandNode cmd) { // Prepare for the next command if (m_isVerbose) m_out.println(m_nExecs + " @" + cmd.m_lineNo + "] " + cmd.m_cmd); // Update some built-in vars updateVars(); // Execute a command (statement) if (cmd.m_cmd == CMD_BLOCK) execBlockCmd(cmd); else if (cmd.m_cmd == CMD_APPEND) execAppendCmd(cmd); else if (cmd.m_cmd == CMD_BINARY || cmd.m_cmd == CMD_TEXT) execModeCmd(cmd); else if (cmd.m_cmd == CMD_BREAK) execBreakCmd(cmd); else if (cmd.m_cmd == CMD_CDUP) execCdupCmd(cmd); else if (cmd.m_cmd == CMD_CHDIR) execChdirCmd(cmd); else if (cmd.m_cmd == CMD_CLOSE) execCloseCmd(cmd); else if (cmd.m_cmd == CMD_CONNECT) execUnknownCmd(cmd); //+FIXME else if (cmd.m_cmd == CMD_CONTINUE) execContinueCmd(cmd); else if (cmd.m_cmd == CMD_DELETE) execDeleteCmd(cmd); else if (cmd.m_cmd == CMD_DIR) execDirCmd(cmd); else if (cmd.m_cmd == CMD_ECHO) execEchoCmd(cmd); else if (cmd.m_cmd == CMD_EXEC) execUnknownCmd(cmd); //+FIXME else if (cmd.m_cmd == CMD_FILENAME) execFilenameCmd(cmd); else if (cmd.m_cmd == CMD_FOR) execUnknownCmd(cmd); //+FIXME else if (cmd.m_cmd == CMD_FOREACH) execForeachCmd(cmd); else if (cmd.m_cmd == CMD_GET) execGetCmd(cmd); else if (cmd.m_cmd == CMD_GLOB) execUnknownCmd(cmd); //+FIXME else if (cmd.m_cmd == CMD_GOTO) execGotoCmd(cmd); else if (cmd.m_cmd == CMD_HELP) execUnknownCmd(cmd); //+FIXME else if (cmd.m_cmd == CMD_IF) execIfCmd(cmd); else if (cmd.m_cmd == CMD_LCHDIR) execLocalChdirCmd(cmd); else if (cmd.m_cmd == CMD_MGET) execUnknownCmd(cmd); //+FIXME else if (cmd.m_cmd == CMD_MKDIR) execMkdirCmd(cmd); else if (cmd.m_cmd == CMD_MPUT) execUnknownCmd(cmd); //+FIXME else if (cmd.m_cmd == CMD_NOP) execNopCmd(cmd); else if (cmd.m_cmd == CMD_OPEN) execOpenCmd(cmd); else if (cmd.m_cmd == CMD_PRINT) execPrintCmd(cmd); else if (cmd.m_cmd == CMD_PUT) execPutCmd(cmd); else if (cmd.m_cmd == CMD_PWD) execPwdCmd(cmd); else if (cmd.m_cmd == CMD_READ) execUnknownCmd(cmd); //+FIXME else if (cmd.m_cmd == CMD_RENAME) execRenameCmd(cmd); else if (cmd.m_cmd == CMD_REPEAT) execRepeatCmd(cmd); else if (cmd.m_cmd == CMD_RETURN) execUnknownCmd(cmd); //+FIXME else if (cmd.m_cmd == CMD_RMDIR) execRmdirCmd(cmd); else if (cmd.m_cmd == CMD_SET) execSetCmd(cmd); else if (cmd.m_cmd == CMD_SHELL) execShellCmd(cmd); else if (cmd.m_cmd == CMD_SLEEP) execSleepCmd(cmd); else if (cmd.m_cmd == CMD_STATUS) execUnknownCmd(cmd); //+FIXME else if (cmd.m_cmd == CMD_SYSTEM) execUnknownCmd(cmd); //+FIXME else if (cmd.m_cmd == CMD_TIMEOUT) execUnknownCmd(cmd); //+FIXME else if (cmd.m_cmd == CMD_USER) execUserCmd(cmd); else if (cmd.m_cmd == CMD_VAR) execVarCmd(cmd); else if (cmd.m_cmd == CMD_WHILE) execWhileCmd(cmd); else if (cmd.m_cmd == CMD_WRITE) execUnknownCmd(cmd); //+FIXME else if (cmd.m_cmd == CMD_EXIT) execExitCmd(cmd); else if (cmd.m_cmd == CMD_FUNC) { /* Do nothing */ } else if (cmd.m_cmd == CMD_LABEL) { /* Do nothing */ } else if (cmd.m_cmd == CMD_X_INTERRUPT) execXInterruptCmd(cmd); else if (cmd.m_cmd == CMD_X_SESSIONS) execXSessionsCmd(cmd); else if (cmd.m_cmd == CMD_X_STACK) execXStackCmd(cmd); else if (cmd.m_cmd == CMD_X_VARS) execXVarsCmd(cmd); else if (cmd.m_cmd == CMD_X_VERBOSE) execXVerboseCmd(cmd); else { ///+INCOMPLETE, error m_out.println(m_fname + ":" + cmd.m_lineNo + ":*** Unsupported command: " + cmd.m_cmd + " (" + cmd.m_lineNo + ")"); } } /*************************************************************************** * Update the built-in vars prior to executing the next command node. * * @since 1.50, 2007-08-01 */ private void updateVars() { long n; String s; // Update $Time n = (new Date()).getTime(); if (n > m_time) { m_time = n; setGlobalNumVar(VAR_TIME, n); } // Update $Random do { n = m_rand.nextLong(); } while (n > 999999999999999999L); s = "000000000000000000" + (n >= 0 ? n : -n); s = s.substring(s.length() - 18); setGlobalStrVar(VAR_RANDOM, s); } ///+TEMPORARY private void execUnknownCmd(CommandNode cmd) { m_out.println(m_fname + ":" + cmd.m_lineNo + ":*** Command not implemented: " + cmd.m_cmd + " (" + cmd.m_lineNo + ")"); } /*************************************************************************** * Crested a nested block statement. * * @param def * Definition of the block statement. * * @param cmds * List of commands within the block body. * * @since 1.8, 2007-03-23 */ private void execANewBlock(CommandNode cmd, BlockDef def, CommandNode cmds) { // Push the current execution frame and start a new one m_frame = new ExecFrame(def, cmds, m_frame); } /*************************************************************************** * Execute the end of a looping command. * * @since 1.8, 2007-03-25 */ private void execALoopEnd() { String type; // Start the next iteration of the loop block m_frame.reset(); type = m_frame.m_scope.m_type; if (type == CMD_FOREACH) { int n; String fname; // Get the next filename in the 'foreach' list for (;;) { n = m_frame.m_fileCnt; if (m_frame.m_files != null && n < m_frame.m_files.size()) { fname = (String) m_frame.m_files.get(n); if (n > 1) m_frame.m_files.set(n-1, null); m_frame.m_fileCnt++; if (fname == null) continue; setFileVars(m_frame.m_host, m_frame.m_dir, fname, (m_frame.m_sess == 0 ? SYS_DIRSEP : "/")); } else endALoop(); break; } } else if (type == CMD_WHILE) { String expr; // Test the controlling expression expr = evalExpr(m_frame.m_expr); if (!isTrue(expr)) endALoop(); } else if (type == CMD_REPEAT) { // Done, perform the next iteration of the loop } } /*************************************************************************** * Terminate a loop (repeat/foreach/while) command. * * @since 1.22, 2007-04-11 */ private void endALoop() { String type; // Pop the current loop frame from the stack do { type = m_frame.m_scope.m_type; m_frame = m_frame.pop(); } while (m_frame != null && type == CMD_BLOCK); } /*************************************************************************** * Execute a block statement command. * *

* Format *

* (CMD_BLOCK, {@link BlockDef}, stmts) * * @since 1.1, 2007-03-16 */ private void execBlockCmd(CommandNode cmd) { BlockDef def; CommandNode cmds; // Push the current execution frame and start a new block frame def = (BlockDef) cmd.m_args[0]; cmds = (CommandNode) cmd.m_args[1]; execANewBlock(cmd, def, cmds); } /*************************************************************************** * Execute an "append" command. * *

* Format *

* (CMD_APPEND, sess, path, [path]) * * @since 1.50, 2007-08-01 */ private void execAppendCmd(CommandNode cmd) { int sess; String src; String dst; // Format: (append, sess, path, [path]) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); src = evalExpr(cmd.m_args[1]).substring(1); if (cmd.m_args[2] != null) dst = evalExpr(cmd.m_args[2]).substring(1); else { int p; dst = src; p = dst.lastIndexOf('/'); if (p < 0) p = dst.lastIndexOf('\\'); if (p >= 0) dst = dst.substring(p+1); } if (m_isVerbose) m_out.println("> append &" + sess + " '" + src + "'" + (dst != null ? " '" + dst + "'": "")); // Append (send) a file to the remote system try { checkSession(sess); m_sess[sess-1].appendFile(src, dst); } catch (IOException ex) { handleException(ex, cmd, "Can't append/send file"); } } /*************************************************************************** * Execute a "break" command. * *

* Format *

* (CMD_BREAK, [name], [stmt], {@link BlockDef}) * * @since 1.8, 2007-03-23 */ private void execBreakCmd(CommandNode cmd) { String name; CommandNode stmt; BlockDef blk; // Format: (break, [name]) name = (String) cmd.m_args[0]; stmt = (CommandNode) cmd.m_args[1]; blk = (BlockDef) cmd.m_args[2]; if (m_isVerbose) { if (name == null) m_out.println("> break"); else m_out.println("> break " + name + "@" + stmt.m_lineNo); } // Terminate the current loop(s) if (name == null) endALoop(); else { // Unwind the stack until the target loop frame is reached while (m_frame != null && m_frame.m_scope != blk) m_frame = m_frame.pop(); } } /*************************************************************************** * Execute a "cdup" ("up") command. * *

* Format *

* (CMD_CDUP, sess) * * @since 1.33, 2007-04-18 */ private void execCdupCmd(CommandNode cmd) { int sess; // Format: (cdup, sess) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); if (m_isVerbose) m_out.println("> cdup &" + sess); // Change the current directory, up a level try { String path; checkSession(sess); m_sess[sess-1].setRemoteDirUp(); path = m_sess[sess-1].getRemoteDir(); setGlobalStrVar(VAR_REMOTEDIR, path); setGlobalStrVar(VAR_REMOTEDIR, sess, path); } catch (IOException ex) { handleException(ex, cmd, "Can't change directory up"); } } /*************************************************************************** * Execute a "close" command. * *

* Format *

* (CMD_CLOSE, sess) * * @since 1.15, 2007-04-01 */ private void execCloseCmd(CommandNode cmd) { int sess; String host = "(unknown)"; // Format: (close, sess) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); if (m_isVerbose) m_out.println("> close &" + sess); // Close (disconnect) an FTP connection try { if (sess < 1 || sess > MAX_SESSIONS) throw new IOException("Bad session number: " + sess); if (m_sess[sess-1] == null || !m_sess[sess-1].isConnected()) return; host = m_sess[sess-1].getHost(); m_sess[sess-1].disconnect(); //m_out.println("# Connection &" + sess + " closed: " + host); } catch (IOException ex) { handleException(ex, cmd, "Can't disconnect from: " + host); } } /*************************************************************************** * Execute a "chdir" command. * *

* Format *

* (CMD_CHDIR, sess, dir) * * @since 1.31, 2007-04-16 */ private void execChdirCmd(CommandNode cmd) { int sess; String dir; // Format: (chdir, sess, dir) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); dir = evalExpr(cmd.m_args[1]).substring(1); if (m_isVerbose) m_out.println("> cd &" + sess + " '" + dir + "'"); // Change the current remote directory try { String path; checkSession(sess); m_sess[sess-1].setRemoteDir(dir); path = m_sess[sess-1].getRemoteDir(); setGlobalStrVar(VAR_REMOTEDIR, path); setGlobalStrVar(VAR_REMOTEDIR, sess, path); } catch (IOException ex) { handleException(ex, cmd, "Can't change remote directory"); } } /*************************************************************************** * Execute a "continue" command. * *

* Format *

* (CMD_CONTINUE, [name], [stmt], {@link BlockDef}) * * @since 1.10, 2007-03-26 */ private void execContinueCmd(CommandNode cmd) { String name; CommandNode stmt; BlockDef blk; // Format: (continue, [name]) name = (String) cmd.m_args[0]; stmt = (CommandNode) cmd.m_args[1]; blk = (BlockDef) cmd.m_args[2]; if (m_isVerbose) { if (name == null) m_out.println("> continue"); else m_out.println("> continue " + name + "@" + stmt.m_lineNo); } // Skip the rest of the commands in the current loop(s) if (name == null) m_frame.m_pc = null; else { // Unwind the stack until the target loop frame is reached while (m_frame != null && m_frame.m_scope.m_outer != blk) m_frame = m_frame.pop(); // Skip the rest of the loop body commands m_frame.m_pc = null; } } /*************************************************************************** * Execute a "delete" command. * *

* Format *

* (CMD_DELETE, sess, file...) * * @since 1.41, 2007-05-11 */ private void execDeleteCmd(CommandNode cmd) { int sess; // Format: (delete, sess, file) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); // Delete files for (int i = 1; i < cmd.m_args.length; i++) { String file; // Delete a file file = evalExpr(cmd.m_args[i]).substring(1); if (m_isVerbose) m_out.println("> delete &" + sess + " '" + file + "'"); try { checkSession(sess); m_sess[sess-1].removeFile(file); } catch (IOException ex) { handleException(ex, cmd, "Can't delete file"); } } } /*************************************************************************** * Execute a "dir" command. * *

* Format *

* (CMD_DIR, sess, "full"|"terse", [max], * [path, ...]) * * @since 1.6, 2007-03-21 */ private void execDirCmd(CommandNode cmd) { int sess; String full; boolean isFull; int max; String path; String paths; // Format: (dir, sess, full, [max], [path...]) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); full = (String) cmd.m_args[1]; isFull = full.equals("full"); max = (int) cvtToInt(evalExpr(cmd.m_args[2])); paths = ""; for (int i = 3; i < cmd.m_args.length; i++) { path = evalExpr(cmd.m_args[i]); if (i > 3) paths += ' '; paths += path.substring(1); } if (m_isVerbose) m_out.println((isFull ? "> dir &" : "> ls &") + sess + " '" + paths + "' max " + max); // List the directory try { checkSession(sess); if (isFull) m_sess[sess-1].getDirectoryList(paths, max, m_outS); else m_sess[sess-1].getDirectoryNames(paths, max, m_outS); m_out.flush(); } catch (IOException ex) { handleException(ex, cmd, "Can't get directory listing"); } } /*************************************************************************** * Execute an "echo" command. * *

* Format *

* (CMD_ECHO, ['-n'], '>'|'>>', [Path], * Term, ...) * * @since 1.1, 2007-03-16 */ private void execEchoCmd(CommandNode cmd) { String nl; String redirect; String path; // Format: (echo, ['-n'], '>'|'>>', [path], [expr...]) nl = (String) cmd.m_args[0]; redirect = (String) cmd.m_args[1]; path = (String) cmd.m_args[2]; /*+++INCOMPLETE ...handle 'path' and 'redirect' +++*/ if (m_isVerbose) m_out.println("> echo (" + (cmd.m_args.length - 3) + ")"); // Print the arguments for (int i = 3; i < cmd.m_args.length; i++) { if (i > 3) m_out.print(' '); m_out.print(evalExpr(cmd.m_args[i]).substring(1)); } // Print a newline if (nl == null || m_isVerbose) { m_out.println(); m_out.flush(); } } /*************************************************************************** * Execute an "exit" command. * *

* Format *

* (CMD_EXIT, [Term]) * * @since 1.5, 2007-03-20 */ private void execExitCmd(CommandNode cmd) { String expr; String val; // Format: (exit, expr) val = evalExpr(cmd.m_args[0]); if (val != null) setGlobalVar(VAR_ERROR, val); m_frame.m_pc = null; m_exit = true; } /*************************************************************************** * Execute a "filename" command. * *

* Format *

* (CMD_FILENAME, name) * * @since 1.16, 2007-04-03 */ private void execFilenameCmd(CommandNode cmd) { String name; // Format: (filename, name) name = (String) cmd.m_args[0]; if (name == null || name.equals("")) name = "-"; if (m_isVerbose) m_out.println("> filename \"" + name + "\""); m_fname = name; setGlobalStrVar(VAR_FILENAME, m_fname); } /*************************************************************************** * Execute a "foreach" command. * *

* Format *

* (CMD_FOREACH, sess, {@link BlockDef}, stmt, * in, max, pattern...) * * @since 1.22, 2007-04-11 */ private void execForeachCmd(CommandNode cmd) { int sess; // Format: (foreach, sess, block, stmt, [in], [max], pattern...) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); if (sess == 0) execForeachLocal(cmd); else execForeachRemote(cmd, sess); } /*************************************************************************** * Execute a remote "foreach" command. * *

* Format *

* (CMD_FOREACH, sess, {@link BlockDef}, stmt, * in, max, pattern...) * * @since 1.32, 2007-04-17 */ private void execForeachRemote(CommandNode cmd, int sess) { BlockDef def; CommandNode cmds; String path; int max; String[] patterns; ForeachFilter filt; // Format: (foreach, sess, block, stmt, [in], [max], pattern...) def = (BlockDef) cmd.m_args[1]; cmds = (CommandNode) cmd.m_args[2]; path = evalExpr(cmd.m_args[3]).substring(1); max = (int) cvtToInt(evalExpr(cmd.m_args[4])); // Get the list of filename patterns to find patterns = new String[cmd.m_args.length - 5]; for (int i = 5; i < cmd.m_args.length; i++) patterns[i-5] = evalExpr(cmd.m_args[i]).substring(1); if (m_isVerbose) m_out.println("> foreach &" + sess); try { // Build a filename pattern matcher filt = new ForeachFilter(patterns, true); } catch (IllegalArgumentException ex) { // Malformed pattern handleException(ex, cmd, "Bad operand"); setFileVars("", "", "", "/"); return; } try { ArrayList files; FTPClientAdapter ftp; // Retrieve a list of filenames from the FTP session checkSession(sess); ftp = m_sess[sess-1]; files = ftp.getDirectoryNames(path, filt, max); if (files != null && files.size() > 0) { // Push the current execution frame and start a new loop frame execANewBlock(cmd, def, cmds); m_frame.m_sess = sess; m_frame.m_host = ftp.getHost(); m_frame.m_dir = ftp.getRemoteDir(); m_frame.m_files = files; m_frame.m_fileCnt = 0; // Start the first 'foreach' loop iteration execALoopEnd(); } else setFileVars("", "", "", "/"); } catch (IOException ex) { handleException(ex, cmd, "Can't get filename list"); setFileVars("", "", "", "/"); } } /*************************************************************************** * Execute a local "foreach" command. * *

* Format *

* (CMD_FOREACH, sess=0, {@link BlockDef}, stmt, * in, max, pattern...) * * @since 1.32, 2007-04-17 */ private void execForeachLocal(CommandNode cmd) { BlockDef def; CommandNode cmds; String path; int max; String[] patterns; ForeachFilter filt; // Format: (foreach, sess=0, block, stmt, [in], [max], pattern...) def = (BlockDef) cmd.m_args[1]; cmds = (CommandNode) cmd.m_args[2]; path = evalExpr(cmd.m_args[3]).substring(1); max = (int) cvtToInt(evalExpr(cmd.m_args[4])); // Get the list of filename patterns to find patterns = new String[cmd.m_args.length - 5]; for (int i = 5; i < cmd.m_args.length; i++) patterns[i-5] = evalExpr(cmd.m_args[i]).substring(1); if (m_isVerbose) m_out.println("> foreach &0"); try { // Build a filename pattern matcher filt = new ForeachFilter(patterns); filt.setMax(max); } catch (IllegalArgumentException ex) { // Malformed pattern handleException(ex, cmd, "Bad operand"); setFileVars("", "", "", SYS_DIRSEP); return; } try { File dir; String[] list; ArrayList files; ///+REDO, this does not work correctly with absolute 'in' paths (Java bug) ///+SEE also evalTestExpr() // Retrieve a list of filenames from a local directory if (path.equals("")) dir = m_localDir; /*---OLD else if (isAbsFilename(path)) dir = new File(path); else dir = new File(m_localDir, path); ---*/ else { //+THIS is not quite right if m_localDir/path missing but ./path exists dir = new File(m_localDir, path); dir = new File(dir.getCanonicalPath()); if (!dir.exists()) dir = new File(path); dir = new File(dir.getCanonicalPath()); } //m_out.println("% foreach &0 dir='" + dir.getPath() + "'"); if (!dir.isDirectory()) throw new IOException( "Not a directory: '" + dir.getPath() + "'"); list = dir.list(filt); if (list != null && list.length > 0) { files = new ArrayList(list.length); for (int i = 0; i < list.length; i++) { files.add(list[i]); list[i] = null; } // Push the current execution frame and start a new loop frame execANewBlock(cmd, def, cmds); m_frame.m_sess = 0; m_frame.m_host = "local"; m_frame.m_dir = dir.getPath(); m_frame.m_files = files; m_frame.m_fileCnt = 0; // Start the first 'foreach' loop iteration execALoopEnd(); } else setFileVars("", "", "", SYS_DIRSEP); } catch (IOException ex) { handleException(ex, cmd, "Can't get local filename list"); setFileVars("", "", "", SYS_DIRSEP); } } /*************************************************************************** * Execute a "get" command. * *

* Format *

* (CMD_GET, sess, path, [path]) * * @since 1.13, 2007-03-30 */ private void execGetCmd(CommandNode cmd) { int sess; String src; String dst; // Format: (get, sess, path, [path]) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); src = evalExpr(cmd.m_args[1]).substring(1); if (cmd.m_args[2] != null) dst = evalExpr(cmd.m_args[2]).substring(1); else { int p; dst = src; p = dst.lastIndexOf('/'); if (p < 0) p = dst.lastIndexOf('\\'); if (p >= 0) dst = dst.substring(p+1); } if (m_isVerbose) m_out.println("> get &" + sess + " '" + src + "'" + (dst != null ? " '" + dst + "'": "")); // Get (receive) a file from the remote system try { checkSession(sess); m_sess[sess-1].getFile(src, dst); } catch (IOException ex) { handleException(ex, cmd, "Can't get/receive remote file"); } } /*************************************************************************** * Execute a "goto" command. * *

* Format *

* (CMD_GOTO, name, stmt, {@link BlockDef}) * * @since 1.6, 2007-03-21 */ private void execGotoCmd(CommandNode cmd) { String name; CommandNode stmt; BlockDef blk; // Format: (goto, name, stmt, block) name = (String) cmd.m_args[0]; stmt = (CommandNode) cmd.m_args[1]; blk = (BlockDef) cmd.m_args[2]; if (m_isVerbose) m_out.println("> goto " + name + "@" + blk.m_name); // Unwind the frame stack until the goto target frame is reached while (m_frame != null && blk != m_frame.m_scope) m_frame = m_frame.pop(); // Establish the goto target as the next executable command m_frame.m_pc = stmt; } /*************************************************************************** * Execute an "if" command. * *

* Format *

* (CMD_IF, Expr, Stmt, [Stmt]) * * @since 1.9, 2007-03-25 */ private void execIfCmd(CommandNode cmd) { String expr; CommandNode stmt1; CommandNode stmt2; // Format: (if, expr, stmt, [stmt]) expr = evalExpr(cmd.m_args[0]); stmt1 = (CommandNode) cmd.m_args[1]; stmt2 = (CommandNode) cmd.m_args[2]; // Choose either the 'then' or 'else' substatement if (isTrue(expr)) { stmt1.m_next = cmd.m_next; m_frame.m_pc = stmt1; } else if (stmt2 != null) { stmt2.m_next = cmd.m_next; m_frame.m_pc = stmt2; } } /*************************************************************************** * Execute an "lchdir" command. * *

* Format *

* (CMD_LCHDIR, sess, dir) * * @since 1.53, 2008-09-14 */ private void execLocalChdirCmd(CommandNode cmd) { int sess; String dir; // Format: (chdir, sess, dir) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); dir = evalExpr(cmd.m_args[1]).substring(1); if (m_isVerbose) m_out.println("> lcd &" + sess + " '" + dir + "'"); // Change the current local directory try { String path; if (sess == 0) { File dirname; dirname = new File(dir); if (!dirname.exists()) throw new FTPException("Directory does not exist: \"" + dir + "\""); if (!dirname.isDirectory()) throw new FTPException("Not a directory: \"" + dir + "\""); m_localDir = dirname; path = dirname.getPath(); setGlobalStrVar(VAR_LOCALDIR, path); } else { checkSession(sess); m_sess[sess-1].setLocalDir(dir); path = m_sess[sess-1].getLocalDir(); setGlobalStrVar(VAR_LOCALDIR, path); setGlobalStrVar(VAR_LOCALDIR, sess, path); } } catch (IOException ex) { handleException(ex, cmd, "Can't change local directory"); } } /*************************************************************************** * Execute a "mkdir" command. * *

* Format *

* (CMD_MKDIR, sess, dir) * * @since 1.31, 2007-04-16 */ private void execMkdirCmd(CommandNode cmd) { int sess; String dir; // Format: (mkdir, sess, dir) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); dir = evalExpr(cmd.m_args[1]).substring(1); if (m_isVerbose) m_out.println("> mkdir &" + sess + " '" + dir + "'"); // Create a directory try { checkSession(sess); m_sess[sess-1].createDirectory(dir); } catch (IOException ex) { handleException(ex, cmd, "Can't create directory"); } } /*************************************************************************** * Execute an "ascii" or "binary" mode command. * *

* Format *

* (CMD_BINARY, sess)
* (CMD_TEXT, sess) * * @since 1.32, 2007-04-17 */ private void execModeCmd(CommandNode cmd) { int sess; // Format: (binary|text, sess) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); if (m_isVerbose) m_out.println((cmd.m_cmd == CMD_TEXT ? "ascii &" : "binary &") + sess); // Set the data transfer mode for an FTP connection try { checkSession(sess); m_sess[sess-1].setTextMode(cmd.m_cmd == CMD_TEXT); } catch (IOException ex) { handleException(ex, cmd, "Can't set data mode"); } } /*************************************************************************** * Execute a "nop" command. * *

* Format *

* (CMD_NOP) * * @since 1.22, 2007-04-11 */ private void execNopCmd(CommandNode cmd) { // No nothing } /*************************************************************************** * Execute an "open" command. * *

* Format *

* (CMD_OPEN, sess, host, [port]) * * @since 1.6, 2007-03-21 */ private void execOpenCmd(CommandNode cmd) { int sess; String host; String port; // Format: (open, sess, host, [port]) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); host = evalExpr(cmd.m_args[1]).substring(1); port = null; if (cmd.m_args[2] != null) port = evalExpr(cmd.m_args[2]); if (m_isVerbose) m_out.println("> open &" + sess + " '" + host + "' " + (port != null ? "'" + port.substring(1) + "'" : "-")); // Open (connect to) an FTP connection try { if (sess < 1 || sess > MAX_SESSIONS) throw new IOException("Bad session number: " + sess); if (m_sess[sess-1] == null) m_sess[sess-1] = new FTPClient(); m_sess[sess-1].setHost(host); if (port != null) m_sess[sess-1].setCommandPort((int) cvtToInt(port)); m_sess[sess-1].connect(); //m_out.println("# Connection &" + sess + " opened: " // + m_sess[sess-1].getHost()); host = m_sess[sess-1].getHost(); setGlobalStrVar(VAR_HOST, host); setGlobalStrVar(VAR_HOST, sess, host); port = m_sess[sess-1].getCommandPort() + ""; setGlobalStrVar(VAR_PORT, port); setGlobalStrVar(VAR_PORT, sess, port); } catch (IOException ex) { handleException(ex, cmd, "Can't connect to: " + host); return; } // Log into the FTP connection try { m_sess[sess-1].login(); //m_out.println("# Logged into &" + sess + ": " // + m_sess[sess-1].getHost()); } catch (IOException ex) { handleException(ex, cmd, "Can't login to: " + host); } } /*************************************************************************** * Execute a "print" command. * *

* Format *

* (CMD_PRINT, '>'|'>>', [Path], Term, ...) * * @since 1.22, 2007-04-11 */ private void execPrintCmd(CommandNode cmd) { String nl; String redirect; String path; // Format: (print, '>'|'>>', [path], [expr...]) redirect = (String) cmd.m_args[0]; path = (String) cmd.m_args[1]; /*+++INCOMPLETE ...handle 'path' and 'redirect' +++*/ if (m_isVerbose) m_out.println("> print (" + (cmd.m_args.length - 3) + ")"); // Print the arguments for (int i = 2; i < cmd.m_args.length; i++) m_out.print(evalExpr(cmd.m_args[i]).substring(1)); m_out.flush(); } /*************************************************************************** * Execute a "put" command. * *

* Format *

* (CMD_PUT, sess, path, [path]) * * @since 1.13, 2007-03-30 */ private void execPutCmd(CommandNode cmd) { int sess; String src; String dst; // Format: (put, sess, path, [path]) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); src = evalExpr(cmd.m_args[1]).substring(1); if (cmd.m_args[2] != null) dst = evalExpr(cmd.m_args[2]).substring(1); else { int p; dst = src; p = dst.lastIndexOf('/'); if (p < 0) p = dst.lastIndexOf('\\'); if (p >= 0) dst = dst.substring(p+1); } if (m_isVerbose) m_out.println("> put &" + sess + " '" + src + "'" + (dst != null ? " '" + dst + "'": "")); // Put (send) a file to the remote system try { checkSession(sess); m_sess[sess-1].putFile(src, dst); } catch (IOException ex) { handleException(ex, cmd, "Can't put/send file"); } } /*************************************************************************** * Execute a "pwd" command. * *

* Format *

* (CMD_PWD, sess) * * @since 1.8, 2007-03-22 */ private void execPwdCmd(CommandNode cmd) { int sess; // Format: (pwd, sess) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); if (m_isVerbose) m_out.println("> pwd &" + sess); // Retrieve the current remote directory try { String path; checkSession(sess); path = m_sess[sess-1].getRemoteDir(); //m_out.println("# Current directory &" + sess + ": " + path); setGlobalStrVar(VAR_REMOTEDIR, path); setGlobalStrVar(VAR_REMOTEDIR, sess, path); } catch (IOException ex) { handleException(ex, cmd, "Can't get remote directory"); } } /*************************************************************************** * Execute a "rename" command. * *

* Format *

* (CMD_RENAME, sess, old, new) * * @since 1.43, 2007-05-14 */ private void execRenameCmd(CommandNode cmd) { int sess; String from; String to; // Format: (rename, sess, from, to) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); from = evalExpr(cmd.m_args[1]).substring(1); to = evalExpr(cmd.m_args[2]).substring(1); // Rename a file/directory if (m_isVerbose) m_out.println("> rename &" + sess + " '" + from + "' '" + to + "'"); try { checkSession(sess); m_sess[sess-1].rename(from, to); } catch (IOException ex) { handleException(ex, cmd, "Can't rename file: '" + from + "'"); } } /*************************************************************************** * Execute a "repeat" command. * *

* Format *

* (CMD_REPEAT, {@link BlockDef}, stmt) * * @since 1.8, 2007-03-22 */ private void execRepeatCmd(CommandNode cmd) { BlockDef def; CommandNode cmds; // Push the current execution frame and start a new loop frame def = (BlockDef) cmd.m_args[0]; cmds = (CommandNode) cmd.m_args[1]; execANewBlock(cmd, def, cmds); } /*************************************************************************** * Execute a "rmdir" command. * *

* Format *

* (CMD_RMDIR, sess, dir...) * * @since 1.31, 2007-04-16 */ private void execRmdirCmd(CommandNode cmd) { int sess; // Format: (rmdir, sess, dir) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); // Delete directories for (int i = 1; i < cmd.m_args.length; i++) { String dir; // Delete a directory dir = evalExpr(cmd.m_args[i]).substring(1); if (m_isVerbose) m_out.println("> rmdir &" + sess + " '" + dir + "'"); try { checkSession(sess); m_sess[sess-1].removeDirectory(dir); } catch (IOException ex) { handleException(ex, cmd, "Can't delete directory"); } } } /*************************************************************************** * Execute a "set" command. * *

* Format *

* (CMD_SET, name, {@link BlockDef}, index, Expr) * * @since 1.2, 2007-03-17 */ private void execSetCmd(CommandNode cmd) { String var; String ind; String val; BlockDef def; int nest; // Format: (set, name, nest, index, expr) var = (String) cmd.m_args[0]; def = (BlockDef) cmd.m_args[1]; ind = (cmd.m_args[2] == null ? null : evalExpr(cmd.m_args[2])); val = evalExpr(cmd.m_args[3]); nest = m_frame.m_depth - def.m_depth; if (m_isVerbose) { String v; String sfx = null; // Pretty-print the var assignment m_out.print("> set " + var); v = ind; if (v != null) { if (v.length() > 30) { sfx = "... (" + (v.length()-1) + ")"; v = v.substring(0, 30); } m_out.print('['); if (v.charAt(0) == 'n') m_out.print(v.substring(1)); else { ExecFrame.dumpString(v, m_out); if (sfx != null) m_out.print(sfx); } m_out.print(']'); } m_out.print(" = "); v = val; if (v.length() > 50) { sfx = "... (" + (v.length()-1) + ")"; v = v.substring(0, 50); } if (v.charAt(0) == 'n') m_out.print(v.substring(1)); else { ExecFrame.dumpString(v, m_out); if (sfx != null) m_out.print(sfx); } m_out.println(); } // Assign a new value to the var if (ind != null) ind = var + '[' + ind.substring(1); m_frame.setVar(var, nest, ind, val); } /*************************************************************************** * Execute a "!" shell command. * *

* Format *

* (CMD_SHELL, expr...) * * @since 1.33, 2007-04-18 */ private void execShellCmd(CommandNode cmd) { String[] argv; // Build the child shell command argv = new String[cmd.m_args.length]; for (int i = 0; i < argv.length; i++) argv[i] = evalExpr(cmd.m_args[i]); if (m_isVerbose) { m_out.print("> !"); for (int i = 0; i < argv.length; i++) { m_out.print(' '); ExecFrame.dumpString(argv[i], m_out); } m_out.println(); } for (int i = 0; i < argv.length; i++) argv[i] = argv[i].substring(1); // Flush all output before running the child shell m_out.flush(); System.out.flush(); System.err.flush(); // Spawn a child shell process try { int rc; // Spawn the child shell process rc = RuntimeExec.exec(argv, null, m_localDir, m_outS, m_errS); setGlobalNumVar(VAR_ERROR, rc); } catch (IOException ex) { handleException(ex, cmd, "Can't execute a shell command: '" + argv[0] + "'"); } } /*************************************************************************** * Execute a "sleep" command. * *

* Format *

* (CMD_SLEEP, expr) * * @since 1.31, 2007-04-16 */ private void execSleepCmd(CommandNode cmd) { String expr; long msec; long now; long then; long later; // Format: (sleep, expr) expr = evalExpr(cmd.m_args[0]); msec = cvtToInt(expr); if (msec <= 0 && m_isVerbose) m_out.println("> sleep -" + (-msec/1000) + " sec"); // Sleep (suspend execution) for the specified time interval now = m_time; then = now + msec; later = 0; while (now < then && !m_stop) { try { int t; // Sleep in 3 sec intervals msec = then - now; t = (int) (msec > 3*1000 ? 3*1000 : msec); if (now >= later) { later = (later == 0 ? now : later) + 60*60*1000; if (m_isVerbose) { expr = "000" + (msec%1000); expr = expr.substring(expr.length() - 3); m_out.println("> sleep " + (msec/1000) + "." + expr + " sec"); m_out.flush(); } } Thread.sleep(t); } catch (Exception ex) { } now = (new Date()).getTime(); } } /*************************************************************************** * Execute a "user" command. * *

* Format *

* (CMD_USER, sess, name, [password]) * * @since 1.6, 2007-03-21 */ private void execUserCmd(CommandNode cmd) { int sess; String name; String pwd; // Format: (user, sess, name, [password]) sess = (int) cvtToInt(evalExpr(cmd.m_args[0])); name = evalExpr(cmd.m_args[1]).substring(1); pwd = ""; if (cmd.m_args[2] != null) pwd = evalExpr(cmd.m_args[2]).substring(1); if (m_isVerbose) m_out.println("> user &" + sess + " '" + name + "' " + (pwd != null ? "'***'" : "")); // Establish the user name and password try { if (sess < 1 || sess > MAX_SESSIONS) throw new IOException("Bad session number: " + sess); if (m_sess[sess-1] == null) m_sess[sess-1] = new FTPClient(); m_sess[sess-1].setUserID(name); m_sess[sess-1].setPassword(pwd); setGlobalStrVar(VAR_USER, name); setGlobalStrVar(VAR_USER, sess, name); setGlobalStrVar(VAR_PASSWORD, pwd); setGlobalStrVar(VAR_PASSWORD, sess, pwd); } catch (IOException ex) { handleException(ex, cmd, "Can't set user info"); } } /*************************************************************************** * Execute a "var" command. * *

* Format *

* (CMD_VAR, name, {@link BlockDef}, [Expr]) * * @since 1.2, 2007-03-17 */ private void execVarCmd(CommandNode cmd) { String var; BlockDef def; String val; // Format: (var, name, expr) var = (String) cmd.m_args[0]; def = (BlockDef) cmd.m_args[1]; val = evalExpr(cmd.m_args[2]); m_frame.defVar(var, val); } /*************************************************************************** * Execute a "while" command. * *

* Format *

* (CMD_WHILE, Expr, {@link BlockDef}, Stmt) * * @since 1.22, 2007-04-11 */ private void execWhileCmd(CommandNode cmd) { BlockDef def; CommandNode cmds; Object expr; // Push the current execution frame and start a new loop frame expr = cmd.m_args[0]; def = (BlockDef) cmd.m_args[1]; cmds = (CommandNode) cmd.m_args[2]; execANewBlock(cmd, def, cmds); m_frame.m_expr = expr; // Start the first loop iteration execALoopEnd(); } /*************************************************************************** * Execute an "%interrupt" special command. * *

* Format *

* (CMD_X_INTERRUPT) * * @since 1.38, 2007-05-08 */ private void execXInterruptCmd(CommandNode cmd) { if (m_isVerbose) m_out.println("> " + cmd.m_cmd); // Simulate an asynchronous interrupt (stop) signal stop(); } /*************************************************************************** * Execute a "%sessions" debugging command. * *

* Format *

* (CMD_X_SESSIONS) * * @since 1.22, 2007-04-11 */ private void execXSessionsCmd(CommandNode cmd) { if (m_isVerbose) m_out.println("> " + cmd.m_cmd); // Display the currently active FTP sessions m_out.println("Sessions:"); for (int i = 1; i <= m_sess.length; i++) { FTPClientAdapter sess; String s; // Display info about an FTP session sess = m_sess[i-1]; if (sess == null) continue; m_out.println("&" + i + (sess.isConnected() ? " connected" : " disconnected")); s = sess.getHost(); s = (s == null ? "" : s); m_out.println(" host '" + s + "' " + sess.getCommandPort() + " " + sess.getDataPort()); s = sess.getUserID(); s = (s == null ? "" : s); m_out.println(" user '" + s + "'"); } } /*************************************************************************** * Execute a "%stack" debugging command. * *

* Format *

* (CMD_X_STACK) * * @since 1.33, 2007-04-18 */ private void execXStackCmd(CommandNode cmd) { if (m_isVerbose) m_out.println("> " + cmd.m_cmd); // Display the current stack frames m_out.println("Stack:"); m_frame.dumpStack(m_out); } /*************************************************************************** * Execute a "%vars" debugging command. * *

* Format *

* (CMD_X_VARS) * * @since 1.22, 2007-04-11 */ private void execXVarsCmd(CommandNode cmd) { // Display the contents of all current vars m_out.println("Vars:"); m_frame.dumpVars(m_out); } /*************************************************************************** * Execute a "%verbose" debugging command. * *

* Format *

* (CMD_X_VERBOSE, expr) * * @since 1.34, 2007-04-27 */ private void execXVerboseCmd(CommandNode cmd) { String val; //if (m_isVerbose) // m_out.println("> " + cmd.m_cmd); // Set the verbosity val = evalExpr(cmd.m_args[0]); if (isTrue(val)) m_isVerbose = true; else m_isVerbose = m_verbose; } /*************************************************************************** * Define a global var and initialize it. * * @param var * Global var name to set. * * @param val * Value to set the var to. * * @since 1.8, 2007-03-23 */ private void defGlobalVar(String name, String val) { m_frame.defVar(name, val); } /*************************************************************************** * Set the value of a global var. * * @param var * Global var name to set. * * @param val * Value to set the var to. * * @since 1.6, 2007-03-21 */ private void setGlobalVar(String name, String val) { m_frame.setVar(name, m_frame.m_depth, null, val); } /*************************************************************************** * Set the string value of a global var. * * @param var * Global var name to set. * * @param val * String value to set the var to (sans the leading 's' prefix). * * @since 1.22, 2007-04-11 */ private void setGlobalStrVar(String name, String val) { m_frame.setVar(name, m_frame.m_depth, null, 's' + val); } /*************************************************************************** * Set the string value of a global var. * * @param var * Global var name to set. * * @param ind * Array index (subscript). * * @param val * String value to set the var to (sans the leading 's' prefix). * * @since 1.48, 2007-05-31 */ private void setGlobalStrVar(String name, int ind, String val) { String elem; elem = name + '[' + ind; m_frame.setVar(name, m_frame.m_depth, elem, 's' + val); } /*************************************************************************** * Set the numeric value of a global var. * * @param var * Global var name to set. * * @param val * Numeric value to set the var to. * * @since 1.22, 2007-04-11 */ private void setGlobalNumVar(String name, long val) { m_frame.setVar(name, m_frame.m_depth, null, "n" + val); } /*************************************************************************** * Set the global vars pertaining to a 'foreach' filename. * * @param host * Name of the remote FTP host where the filename was found. * (E.g., ftp.host.com.) * * @param dir * Remote directory name containing the filename. * (E.g., /users/bob/text.) * * @param file * Name of the found file. This may also contain a directory path prefix. * (E.g., file.txt or text/file.txt.) * * @param sep * Directory component separator (e.g., "/" for Unix, "\" * for MS/Windows). * * @since 1.26, 2007-04-14 */ private void setFileVars(String host, String dir, String file, String sep) { int p; String s; boolean isRoot; ///+REDO, should these tests use sep.charAt(0) instead? // Set the '$F' global vars from the filename p = dir.length(); isRoot = false; if (p == 1 && (dir.charAt(0) == '/' || dir.charAt(0) == '\\')) isRoot = true; if (p > 1 && (dir.charAt(p-1) == '/' || dir.charAt(p-1) == '\\')) { dir = dir.substring(0, p-1); p--; } p = file.lastIndexOf('/'); if (p < 0) p = file.lastIndexOf('\\'); if (p >= 0) { char sepCh; ///+REDO, should this use sep instead of sepCh? sepCh = file.charAt(p); if (!isRoot) dir += sepCh; dir += file.substring(0, p); file = file.substring(p+1); isRoot = false; } setGlobalStrVar(VAR_FILE_HOST, host); setGlobalStrVar(VAR_FILE_PATH, dir); setGlobalStrVar(VAR_FILE, dir + (isRoot ? "" : sep) + file); setGlobalStrVar(VAR_FILE_FILE, file); p = dir.lastIndexOf('/'); s = ""; if (p < 0) p = dir.lastIndexOf('\\'); if (p >= 0) s = dir.substring(p+1); setGlobalStrVar(VAR_FILE_DIR, s); p = file.lastIndexOf('.'); s = file; if (p >= 0) s = file.substring(0, p); setGlobalStrVar(VAR_FILE_NAME, s); s = ""; if (p >= 0) s = file.substring(p); setGlobalStrVar(VAR_FILE_EXT, s); s = ""; if (p >= 0) s = file.substring(p+1); setGlobalStrVar(VAR_FILE_TYPE, s); /*+++INCOMPLETE, not implemented yet setGlobalNumVar(VAR_FILE_GROUP, ...); setGlobalNumVar(VAR_FILE_PERMS, ...); setGlobalNumVar(VAR_FILE_OWNER, ...); setGlobalNumVar(VAR_FILE_SIZE, ...); +++*/ } /*************************************************************************** * Check for a valid FTP session. * * @param sess * Session number (from a '&n' command clause). * * @throws IOException * Thrown if sess is an invalid session index, or if it designates a * session that is not connected. * * @since 1.33, 2007-04-18 */ private void checkSession(int sess) throws IOException { // Check for a valid session index if (sess < 1 || sess > MAX_SESSIONS) throw new IOException("Bad session number: " + sess); if (m_sess[sess-1] == null || !m_sess[sess-1].isConnected()) throw new IOException("Session &" + sess + " not connected"); } /*************************************************************************** * Handle a caught exception. * * @param ex * Exception that was caught. * * @param cmd * Command that caused the exception. * * @param msg * Text message associated with the exception. * * @since 1.24, 2007-04-13 */ private void handleException(Exception ex, CommandNode cmd, String msg) { int code = 1; String reason; // Handle a caught Exception if (ex instanceof FTPException) code = ((FTPException) ex).getErrorCode(); setGlobalNumVar(VAR_ERROR, code); setGlobalStrVar(VAR_ERRORCMD, cmd.m_cmd); setGlobalStrVar(VAR_ERRORMSG, ex.getMessage()); reason = ex.getMessage(); m_out.println(m_fname + ":" + cmd.m_lineNo + ": error: " + msg + (reason != null ? "; " + reason : "")); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Exression evaluation methods /*************************************************************************** * Evaluate an expression. * * @param expr * Expression to evaluate. This is either a {@link CommandNode} tree, a * String literal, or null (which is evaluated as an empty string * ''). * * @return * The resulting value of the expression, as a string. Unknown or * unresolvable terms are treated as an empty string (''), * zero (0), or false. * * @since 1.5, 2007-03-20 */ private String evalExpr(Object expr) { if (expr instanceof CommandNode) return evalSubExpr((CommandNode) expr); else if (expr != null) return evalString((String) expr); else return VAL_EMPTY; } /*************************************************************************** * Evaluate a subexpression. * * @param expr * Expression tree to evaluate. * * @return * The resulting value of the expression, as a string. Unknown or * unresolvable terms are treated as an empty string (''), * zero (0), or false. * * @since 1.5, 2007-03-16 */ private String evalSubExpr(CommandNode expr) { String cmd; String val1; String val2; // Evaluate an expression subtree cmd = expr.m_cmd; if (cmd == CMD_POS || cmd == CMD_NEG) return evalUnaryExpr(expr); else if (cmd == CMD_ADD || cmd == CMD_SUB || cmd == CMD_MUL || cmd == CMD_DIV || cmd == CMD_MOD) return evalArithExpr(expr); else if (cmd == CMD_EQ || cmd == CMD_NE || cmd == CMD_LT || cmd == CMD_LE || cmd == CMD_GT || cmd == CMD_GE) return evalRelExpr(expr); else if (cmd == CMD_MATCH || cmd == CMD_NMATCH) return evalMatchExpr(expr); else if (cmd == CMD_NOT || cmd == CMD_AND || cmd == CMD_OR) return evalLogicalExpr(expr); else if (cmd == CMD_COND) return evalCondExpr(expr); else if (cmd == CMD_BUILTIN) return evalBuiltinExpr(expr); else if (cmd == CMD_TEST) return evalTestExpr(expr); else if (cmd == CMD_SUBSCR) return evalSubscriptExpr(expr); ///...func call ///...CMD_CALL val1 = evalExpr(expr.m_args[0]); if (cmd == CMD_CONCAT) { val2 = evalExpr(expr.m_args[1]); return ('s' + val1.substring(1) + val2.substring(1)); } else { // Unrecognized/unsupported command code m_out.println(m_fname + ":" + expr.m_lineNo + ": Unsupported op: " + cmd); return VAL_EMPTY; } } /*************************************************************************** * Evaluate an array subscript subexpression. * *

* Format *

* (CMD_SUBSCR, array, subscr) * * @since 1.48, 2007-05-31 */ private String evalSubscriptExpr(CommandNode expr) { String cmd; String var; String ind; String name; // Format: (subscr, name, subscr) cmd = expr.m_cmd; var = (String) expr.m_args[0]; ind = evalExpr(expr.m_args[1]).substring(1); // Locate the array (hash) element name = var + '[' + ind; var = m_frame.findVar(var, name); if (var == null) var = VAL_EMPTY; return var; } /*************************************************************************** * Evaluate a unary arithmetic subexpression. * *

* Format *

* (CMD_UNARYOP, expr) * * @since 1.35, 2007-05-02 */ private String evalUnaryExpr(CommandNode expr) { String cmd; long val; // Evaluate an expression subtree cmd = expr.m_cmd; val = cvtToInt(evalExpr(expr.m_args[0])); // Handle unary operators if (cmd == CMD_POS) return ("n" + (+val)); else if (cmd == CMD_NEG) return ("n" + (-val)); // Should not occur, internal error m_out.println(m_fname + ":" + expr.m_lineNo + ": Internal error (evalUnaryExpr): " + cmd); return VAL_ZERO; } /*************************************************************************** * Evaluate an arithmetic subexpression. * *

* Format *

* (CMD_ARITHOP, expr, expr) * * @since 1.20, 2007-04-07 */ private String evalArithExpr(CommandNode expr) { String cmd; long val1; long val2; // Evaluate an expression subtree cmd = expr.m_cmd; val1 = cvtToInt(evalExpr(expr.m_args[0])); val2 = cvtToInt(evalExpr(expr.m_args[1])); // Handle binary operators if (cmd == CMD_ADD) return ("n" + (val1 + val2)); if (cmd == CMD_SUB) return ("n" + (val1 - val2)); if (cmd == CMD_MUL) return ("n" + (val1 * val2)); if (cmd == CMD_DIV || cmd == CMD_MOD) { if (val2 == 0) { m_out.println(m_fname + ":" + expr.m_lineNo + ": Divide by zero"); setGlobalNumVar(VAR_ERROR, 2); setGlobalStrVar(VAR_ERRORCMD, expr.m_cmd); setGlobalStrVar(VAR_ERRORMSG, "Divide by zero"); return VAL_ZERO; } if (cmd == CMD_DIV) return ("n" + (val1 / val2)); else return ("n" + (val1 % val2)); } // Should not occur, internal error m_out.println(m_fname + ":" + expr.m_lineNo + ": Internal error (evalArithExpr): " + cmd); return VAL_ZERO; } /*************************************************************************** * Evaluate a relational (comparison) subexpression. * *

* Format *

* (CMD_RELOP, expr, expr) * * @since 1.20, 2007-04-07 */ private String evalRelExpr(CommandNode expr) { String cmd; String val1; String val2; // Evaluate an expression subtree cmd = expr.m_cmd; val1 = evalExpr(expr.m_args[0]); val2 = evalExpr(expr.m_args[1]); if (val1.charAt(0) == 'n' && val2.charAt(0) == 'n') { long num1; long num2; // Numeric comparison num1 = cvtToInt(val1); num2 = cvtToInt(val2); if (cmd == CMD_EQ) return ((num1 == num2) ? VAL_TRUE : VAL_FALSE); if (cmd == CMD_NE) return ((num1 != num2) ? VAL_TRUE : VAL_FALSE); if (cmd == CMD_LT) return ((num1 < num2) ? VAL_TRUE : VAL_FALSE); if (cmd == CMD_LE) return ((num1 <= num2) ? VAL_TRUE : VAL_FALSE); if (cmd == CMD_GT) return ((num1 > num2) ? VAL_TRUE : VAL_FALSE); if (cmd == CMD_GE) return ((num1 >= num2) ? VAL_TRUE : VAL_FALSE); } else { // String (character) comparison val1 = val1.substring(1); val2 = val2.substring(1); if (cmd == CMD_EQ) return (val1.equals(val2) ? VAL_TRUE : VAL_FALSE); if (cmd == CMD_NE) return (val1.equals(val2) ? VAL_FALSE : VAL_TRUE); if (cmd == CMD_LT) return (val1.compareTo(val2) < 0 ? VAL_TRUE : VAL_FALSE); if (cmd == CMD_LE) return (val1.compareTo(val2) <= 0 ? VAL_TRUE : VAL_FALSE); if (cmd == CMD_GT) return (val1.compareTo(val2) > 0 ? VAL_TRUE : VAL_FALSE); if (cmd == CMD_GE) return (val1.compareTo(val2) >= 0 ? VAL_TRUE : VAL_FALSE); } // Should not occur, internal error m_out.println(m_fname + ":" + expr.m_lineNo + ": Internal error (evalRelExpr): " + cmd); return VAL_FALSE; } /*************************************************************************** * Evaluate a pattern matching subexpression. * *

* Format *

* (CMD_MATCHOP, expr, expr) * * @since 1.42, 2007-05-13 */ private String evalMatchExpr(CommandNode expr) { String fname; String pat; // Evaluate an expression subtree fname = evalExpr(expr.m_args[0]).substring(1); pat = evalExpr(expr.m_args[1]).substring(1); try { boolean res; m_matcher.setPattern(pat); res = m_matcher.matches(fname); if (expr.m_cmd == CMD_NMATCH) res = !res; return (res ? VAL_TRUE : VAL_FALSE); } catch (IllegalArgumentException ex) { // Malformed pattern handleException(ex, expr, "Bad operand"); return VAL_FALSE; } } /*************************************************************************** * Evaluate a logical subexpression. * *

* Format *

* (CMD_LOGICALOP, expr, expr) * * @since 1.20, 2007-04-07 */ private String evalLogicalExpr(CommandNode expr) { String cmd; String val; // Evaluate an expression subtree cmd = expr.m_cmd; val = evalExpr(expr.m_args[0]); if (cmd == CMD_NOT) { return (isTrue(val) ? VAL_FALSE : VAL_TRUE); } else if (cmd == CMD_AND) { if (!isTrue(val)) return VAL_FALSE; val = evalExpr(expr.m_args[1]); return (isTrue(val) ? VAL_TRUE : VAL_FALSE); } else if (cmd == CMD_OR) { if (isTrue(val)) return VAL_TRUE; val = evalExpr(expr.m_args[1]); return (isTrue(val) ? VAL_TRUE : VAL_FALSE); } // Should not occur, internal error m_out.println(m_fname + ":" + expr.m_lineNo + ": Internal error (evalLogicalExpr): " + cmd); return VAL_FALSE; } /*************************************************************************** * Evaluate a conditional (ternary) subexpression. * *

* Format *

* (CMD_COND, expr, expr, expr) * * @since 1.52, 2007-08-10 */ private String evalCondExpr(CommandNode expr) { String val; // Evaluate an expression subtree val = evalExpr(expr.m_args[0]); if (isTrue(val)) val = evalExpr(expr.m_args[1]); else val = evalExpr(expr.m_args[2]); return val; } /*************************************************************************** * Evaluate a file predicate subexpression. * *

* Format *

* (CMD_TEST, optype, expr) * * @since 1.35, 2007-04-30 */ private String evalTestExpr(CommandNode expr) { String cmd; String optype; String fname; // Evaluate a file predicate expression cmd = expr.m_cmd; optype = (String) expr.m_args[0]; fname = evalExpr(expr.m_args[1]).substring(1); try { File f; String res; // Get status info for the filename ///m_out.println(); ///m_out.println("% test local=[" + m_localDir.getCanonicalPath() + "] " /// + (m_localDir.isAbsolute() ? "abs" : "rel")); ///f = new File(fname); ///m_out.println("% test file= [" + f.getCanonicalPath() + "] " /// + (f.isAbsolute() ? "abs" : "rel")); /*---OLD if (isAbsFilename(fname)) f = new File(SYS_DIRSEP + fname); else f = new File(m_localDir, fname); ---*/ //+THIS is not quite right if m_localDir/path missing but ./path exists f = new File(m_localDir, fname); f = new File(f.getCanonicalPath()); if (!f.exists()) f = new File(fname); f = new File(f.getCanonicalPath()); ///+FIXME: '\tmp\foo.tmp' -> 'c:\DRT\Src\java\ftp\tmp\foo.tmp', WRONG! ///+FIX this also in command 'foreach', execForeachLocal() ///m_out.println("% test " + optype + " [" + fname + "] > [" + f.getPath() + "]"); // Evaluate the predicate operator if (optype == CMD_TEST_DIR) res = (f.isDirectory() ? VAL_TRUE : VAL_FALSE); /*+++INCOMPLETE else if (optype == CMD_TEST_EXEC) res = (f.canExecute() ? VAL_TRUE : VAL_FALSE); +++*/ else if (optype == CMD_TEST_EXISTS) res = (f.exists() ? VAL_TRUE : VAL_FALSE); else if (optype == CMD_TEST_FILE) res = (f.isFile() ? VAL_TRUE : VAL_FALSE); else if (optype == CMD_TEST_MODTIME) res = "n" + f.lastModified(); else if (optype == CMD_TEST_READ) res = (f.canRead() ? VAL_TRUE : VAL_FALSE); else if (optype == CMD_TEST_SIZE) res = "n" + f.length(); else if (optype == CMD_TEST_WRITE) res = (f.canWrite() ? VAL_TRUE : VAL_FALSE); else throw new IOException("Unknown file test operator: '" + optype + "'"); return res; } catch (IOException ex) { // Cannot get file status, assume it does not exist //handleException(ex, cmd, "Can't get file status: " + fname); return VAL_FALSE; } } /*************************************************************************** * Evaluate a string expression. * *

* Numeric strings (e.g., '123' and '-0099') evaluate to * numeric values. Strings (words) containing only var substitutions * (e.g., '$name') result in the same value and type as the named * var. All other strings are either sequences of alphanumeric characters * (e.g., 'abc,0123%') or are concatenations of var substitutions * and alphanumeric characters (e.g., 'xx${abc}yy'), both kinds of * which result in non-numeric values. * Note that the word 00${abc}00 is equivalent to the expression * (00.${abc}.00), which results in a non-numeric value. * The special syntax ${$foo} retrieves the value of the environment * variable named foo. Environment variables are always considered * as non-numeric values. * * @param s * String (literal) expression to evaluate. The string can contain embedded * character escape sequences, var names, and printable characters. * * @return * The value of the string, with all embedded var expressions replaced with * their current values. * * @since 1.2, 2007-03-16 */ private String evalString(String s) { StringBuffer buf; String str; boolean isNum; int len; int i; char ch; // Interpret the string contents len = s.length(); if (len <= 1) return VAL_EMPTY; // Interpret the string contents, replacing vars and escape sequences buf = new StringBuffer(len+10); buf.append('s'); isNum = true; i = 1; if (i < len) { // Check for a leading numeric sign ch = s.charAt(i++); if (ch == '+' || ch == '-') buf.append(ch); else i--; } while (i < len) { // Interpret the next portion of the string ch = s.charAt(i++); if (ch == '$' && i < len) { String name; String val; char quote; int bi; // Escape sequence or var name ch = s.charAt(i++); quote = 'x'; switch (ch) { case '$': case '`': case '"': case '\'': // Escape sequence, '$x' isNum = false; buf.append(ch); break; case '{': // Var name, '$abc' or '${abc}' or '${$abc}' quote = '{'; if (i < len) ch = s.charAt(i++); bi = 0; while (ch != '}') { if (bi < m_vbuf.length) m_vbuf[bi++] = ch; if (i >= len) break; ch = s.charAt(i++); } // Retrieve the var expr value if (m_vbuf[0] == '$' && bi > 1) { // Retrieve the named environment variable value name = new String(m_vbuf, 1, bi-1); val = System.getenv(name); if (val != null) { buf.append(val); isNum = false; } } else { // Retrieve the named var value name = new String(m_vbuf, 0, bi); val = m_frame.findVar(name, null); if (val != null) { if (val.charAt(0) != 'n' || buf.length() > 1) isNum = false; buf.append(val.substring(1)); } if (i < len) isNum = false; } break; default: // Unknown '$' escape sequence isNum = false; buf.append('$'); buf.append(ch); break; } } else { buf.append(ch); if (ch < '0' || ch > '9') isNum = false; } } if (isNum) buf.setCharAt(0, 'n'); // Done str = buf.toString(); if (str.equalsIgnoreCase(VAL_TRUE)) str = VAL_TRUE; else if (str.equalsIgnoreCase(VAL_FALSE)) str = VAL_FALSE; return str; } /*************************************************************************** * Evaluate a built-in func subexpression. * *

* Format *

* (CMD_BUILTIN, CMD_FUNCOP, expr, ...) * * @since 1.21, 2007-04-09 */ private String evalBuiltinExpr(CommandNode expr) { String cmd; String op; int nargs; String val1; String val2; String val3; int num2; int num3; String res; // Evaluate a built-in func expression cmd = expr.m_cmd; op = (String) expr.m_args[0]; nargs = expr.m_args.length; val1 = (nargs > 1 ? evalExpr(expr.m_args[1]) : VAL_EMPTY); val2 = (nargs > 2 ? evalExpr(expr.m_args[2]) : VAL_EMPTY); val3 = (nargs > 3 ? evalExpr(expr.m_args[3]) : VAL_EMPTY); if (op == CMD_FUNC_INDEX) res = BuiltinFuncs.funcIndex(val1, val2); else if (op == CMD_FUNC_LCASE) res = BuiltinFuncs.funcLowerCase(val1); else if (op == CMD_FUNC_LEN) res = BuiltinFuncs.funcLen(val1); else if (op == CMD_FUNC_NORM) res = BuiltinFuncs.funcNorm(val1); else if (op == CMD_FUNC_REPL) res = BuiltinFuncs.funcRepl(val1, val2, val3); else if (op == CMD_FUNC_RINDEX) res = BuiltinFuncs.funcRindex(val1, val2); else if (op == CMD_FUNC_SUB) { num2 = (int) cvtToInt(val2); num3 = (int) cvtToInt(val3); if (nargs > 3) res = BuiltinFuncs.funcSubstr(val1, num2, num3); else res = BuiltinFuncs.funcSubstr(val1, num2); } else if (op == CMD_FUNC_TRIM) res = BuiltinFuncs.funcTrim(val1); else if (op == CMD_FUNC_UCASE) res = BuiltinFuncs.funcUpperCase(val1); else res = VAL_EMPTY; return res; } /*************************************************************************** * Convert a string expression into an integer value. * * @param s * String (literal) expression to evaluate. * Numeric strings are composed of an optional leading sign ('+' or * '-') followed by one or more decimal digits ('0' thru * '9'). Empty strings ('') are converted into 0. * Strings of any other form are converted into 1. * * @return * The value of the string as a signed integer, or zero if it an empty string * (''), or 1 if it is a non-empty string but does not contain a * properly formatted numeric value. * * @since 1.6, 2007-03-21 */ private long cvtToInt(String s) { // Sanity checks if (s == null || s.length() <= 1) return 0; try { // Convert the string into an integer if (s.charAt(1) == '+') s = s.substring(1); return Long.parseLong(s.substring(1)); } catch (NumberFormatException ex) { return 1; } } /*************************************************************************** * Evaluate a string value as a boolean (logical) value. * Empty string values ('') are false, all other strings are true. * Number values equal to zero (0, -000) are false, all * other (non-zero) numbers are true. * * @param s * String (literal) value to evaluate. * * @return * True if the string evaluates to a true value, otherwise false. * * @since 1.22, 2007-04-11 */ private boolean isTrue(String expr) { if (expr == null) return false; else if (expr == VAL_FALSE) return false; else if (expr == VAL_TRUE) return true; else if (expr == VAL_EMPTY || expr.equals(VAL_EMPTY)) return false; else if (expr.length() == 0) return false; else if (expr.charAt(0) == 'n') return (cvtToInt(expr) != 0); else if (expr == CMD_FALSE || expr.equals(VAL_FALSE_WD)) return false; else return true; } /*---OLD, NO LONGER USED private boolean isAbsFilename(String fname) { char ch; if (fname.length() < 1) return false; ///+++REDO, to be platform-independent, and to work on DOS with "c:\bin\foo.x" ch = fname.charAt(0); return (ch == '/' || ch == '\\'); } ---*/ } // End Interp.java