//============================================================================== // 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. * * *
* 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
* 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
* 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)
* 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
* (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.
*
*