460 lines
11 KiB
Java
460 lines
11 KiB
Java
/*
|
|
* $Id: Awk.java,v 1.32 2007/11/10 15:30:07 bacon Exp $
|
|
*
|
|
* {License}
|
|
*/
|
|
|
|
package ase.awk;
|
|
|
|
import java.io.*;
|
|
import java.util.HashMap;
|
|
import java.lang.reflect.Method;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
|
|
/**
|
|
* Represents the AWK interpreter engine
|
|
*/
|
|
public abstract class Awk
|
|
{
|
|
private HashMap functionTable;
|
|
|
|
// mode for open_source & close_source
|
|
public static final int SOURCE_READ = 1;
|
|
public static final int SOURCE_WRITE = 2;
|
|
|
|
// depth id
|
|
public static final int DEPTH_BLOCK_PARSE = (1 << 0);
|
|
public static final int DEPTH_BLOCK_RUN = (1 << 1);
|
|
public static final int DEPTH_EXPR_PARSE = (1 << 2);
|
|
public static final int DEPTH_EXPR_RUN = (1 << 3);
|
|
public static final int DEPTH_REX_BUILD = (1 << 4);
|
|
public static final int DEPTH_REX_MATCH = (1 << 5);
|
|
|
|
// options
|
|
public static final int OPTION_IMPLICIT = (1 << 0);
|
|
public static final int OPTION_EXPLICIT = (1 << 1);
|
|
public static final int OPTION_UNIQUEFN = (1 << 2);
|
|
public static final int OPTION_SHADING = (1 << 3);
|
|
public static final int OPTION_SHIFT = (1 << 4);
|
|
public static final int OPTION_IDIV = (1 << 5);
|
|
public static final int OPTION_STRCONCAT = (1 << 6);
|
|
public static final int OPTION_EXTIO = (1 << 7);
|
|
public static final int OPTION_COPROC = (1 << 8);
|
|
public static final int OPTION_BLOCKLESS = (1 << 9);
|
|
public static final int OPTION_BASEONE = (1 << 10);
|
|
public static final int OPTION_STRIPSPACES = (1 << 11);
|
|
public static final int OPTION_NEXTOFILE = (1 << 12);
|
|
public static final int OPTION_CRLF = (1 << 13);
|
|
public static final int OPTION_ARGSTOMAIN = (1 << 14);
|
|
public static final int OPTION_RESET = (1 << 15);
|
|
public static final int OPTION_MAPTOVAR = (1 << 16);
|
|
public static final int OPTION_PABLOCK = (1 << 17);
|
|
|
|
protected final static Reader stdin = new BufferedReader (new InputStreamReader (System.in));
|
|
protected final static Writer stdout = new BufferedWriter (new OutputStreamWriter (System.out));
|
|
|
|
private long awkid;
|
|
|
|
public Awk () throws Exception
|
|
{
|
|
this.awkid = 0;
|
|
this.functionTable = new HashMap ();
|
|
open ();
|
|
}
|
|
|
|
/* == just in case == */
|
|
protected void finalize () throws Throwable
|
|
{
|
|
close ();
|
|
super.finalize ();
|
|
}
|
|
|
|
public void close ()
|
|
{
|
|
if (this.awkid != 0)
|
|
{
|
|
close (this.awkid);
|
|
this.awkid = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parse a source program
|
|
*/
|
|
public void parse () throws Exception
|
|
{
|
|
parse (this.awkid);
|
|
}
|
|
|
|
/**
|
|
* Executes a parsed program
|
|
*/
|
|
public void run (String main, String[] args) throws Exception
|
|
{
|
|
run (this.awkid, main, args);
|
|
}
|
|
|
|
/**
|
|
* Executes a parsed program
|
|
*/
|
|
public void run (String main) throws Exception
|
|
{
|
|
run (this.awkid, main, null);
|
|
}
|
|
|
|
/**
|
|
* Executes a parsed program
|
|
*/
|
|
public void run (String[] args) throws Exception
|
|
{
|
|
run (this.awkid, null, args);
|
|
}
|
|
|
|
/**
|
|
* Executes a parsed program
|
|
*/
|
|
public void run () throws Exception
|
|
{
|
|
run (this.awkid, null, null);
|
|
}
|
|
|
|
/**
|
|
* Makes a request to stop a running program
|
|
*/
|
|
public void stop () throws Exception
|
|
{
|
|
stop (this.awkid);
|
|
}
|
|
|
|
/* == native methods == */
|
|
private native void open () throws Exception;
|
|
protected native void close (long awkid);
|
|
protected native void parse (long awkid) throws Exception;
|
|
protected native void run (long awkid, String main, String[] args) throws Exception;
|
|
protected native void stop (long awkid) throws Exception;
|
|
protected native int getmaxdepth (long awkid, int id) throws Exception;
|
|
protected native void setmaxdepth (long awkid, int id, int depth) throws Exception;
|
|
protected native int getoption (long awkid) throws Exception;
|
|
protected native void setoption (long awkid, int opt) throws Exception;
|
|
protected native boolean getdebug (long awkid) throws Exception;
|
|
protected native void setdebug (long awkid, boolean debug) throws Exception;
|
|
protected native String getword (long awkid, String ow) throws Exception;
|
|
protected native void setword (long awkid, String ow, String nw) throws Exception;
|
|
|
|
|
|
protected native void addfunc (String name, int min_args, int max_args) throws Exception;
|
|
protected native void delfunc (String name) throws Exception;
|
|
native void setfilename (long runid, String name) throws Exception;
|
|
native void setofilename (long runid, String name) throws Exception;
|
|
protected native String strftime (String fmt, long sec);
|
|
protected native String strfgmtime (String fmt, long sec);
|
|
protected native int system (String cmd);
|
|
|
|
|
|
/* == intrinsic functions == */
|
|
public void addFunction (String name, int min_args, int max_args) throws Exception
|
|
{
|
|
addFunction (name, min_args, max_args, name);
|
|
}
|
|
|
|
public void addFunction (String name, int min_args, int max_args, String method) throws Exception
|
|
{
|
|
if (functionTable.containsKey (name))
|
|
{
|
|
throw new Exception (
|
|
"cannot add existing function '" + name + "'",
|
|
Exception.EXIST);
|
|
}
|
|
|
|
functionTable.put (name, method);
|
|
try { addfunc (name, min_args, max_args); }
|
|
catch (Exception e)
|
|
{
|
|
functionTable.remove (name);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
public void deleteFunction (String name) throws Exception
|
|
{
|
|
delfunc (name);
|
|
functionTable.remove (name);
|
|
}
|
|
|
|
protected void handleFunction (
|
|
Context ctx, String name, Return ret, Argument[] args) throws Exception
|
|
{
|
|
String mn = (String)functionTable.get(name);
|
|
// name should always be found in this table.
|
|
// otherwise, there is something wrong with this program.
|
|
|
|
Class c = this.getClass ();
|
|
Class[] a = { Context.class, String.class, Return.class, Argument[].class };
|
|
|
|
try
|
|
{
|
|
Method m = c.getMethod (mn, a);
|
|
m.invoke (this, /*new Object[] {*/ ctx, name, ret, args/*}*/) ;
|
|
}
|
|
catch (java.lang.reflect.InvocationTargetException e)
|
|
{
|
|
/* the underlying method has throw an exception */
|
|
Throwable t = e.getCause();
|
|
if (t == null)
|
|
{
|
|
throw new Exception (null, Exception.BFNIMPL);
|
|
}
|
|
else if (t instanceof Exception)
|
|
{
|
|
throw (Exception)t;
|
|
}
|
|
else
|
|
{
|
|
throw new Exception (
|
|
t.getMessage(), Exception.BFNIMPL);
|
|
}
|
|
}
|
|
catch (java.lang.Exception e)
|
|
{
|
|
throw new Exception (e.getMessage(), Exception.BFNIMPL);
|
|
}
|
|
}
|
|
|
|
/* == depth limiting == */
|
|
public int getMaxDepth (int id) throws Exception
|
|
{
|
|
return getmaxdepth (this.awkid, id);
|
|
}
|
|
|
|
public void setMaxDepth (int ids, int depth) throws Exception
|
|
{
|
|
setmaxdepth (this.awkid, ids, depth);
|
|
}
|
|
|
|
/* == option == */
|
|
public int getOption () throws Exception
|
|
{
|
|
return getoption (this.awkid);
|
|
}
|
|
|
|
public void setOption (int opt) throws Exception
|
|
{
|
|
setoption (this.awkid, opt);
|
|
}
|
|
|
|
/* == debug == */
|
|
public boolean getDebug () throws Exception
|
|
{
|
|
return getdebug (this.awkid);
|
|
}
|
|
|
|
public void setDebug (boolean debug) throws Exception
|
|
{
|
|
setdebug (this.awkid, debug);
|
|
}
|
|
|
|
/* == word replacement == */
|
|
public String getWord (String ow) throws Exception
|
|
{
|
|
return getword (this.awkid, ow);
|
|
}
|
|
|
|
public void setWord (String ow, String nw) throws Exception
|
|
{
|
|
setword (this.awkid, ow, nw);
|
|
}
|
|
|
|
public void unsetWord (String ow) throws Exception
|
|
{
|
|
setword (this.awkid, ow, null);
|
|
}
|
|
|
|
public void unsetAllWords () throws Exception
|
|
{
|
|
setword (this.awkid, null, null);
|
|
}
|
|
|
|
/* == source code management == */
|
|
protected abstract int openSource (int mode);
|
|
protected abstract int closeSource (int mode);
|
|
protected abstract int readSource (char[] buf, int len);
|
|
protected abstract int writeSource (char[] buf, int len);
|
|
|
|
/* == external io interface == */
|
|
protected int openExtio (Extio extio)
|
|
{
|
|
switch (extio.getType())
|
|
{
|
|
case Extio.TYPE_CONSOLE:
|
|
{
|
|
Console con = new Console (this, extio);
|
|
int n = openConsole (con);
|
|
extio.setHandle (con);
|
|
return n;
|
|
}
|
|
|
|
case Extio.TYPE_FILE:
|
|
{
|
|
File file = new File (this, extio);
|
|
int n = openFile (file);
|
|
extio.setHandle (file);
|
|
return n;
|
|
}
|
|
|
|
case Extio.TYPE_PIPE:
|
|
{
|
|
Pipe pipe = new Pipe (this, extio);
|
|
int n = openPipe (pipe);
|
|
extio.setHandle (pipe);
|
|
return n;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
protected int closeExtio (Extio extio)
|
|
{
|
|
switch (extio.getType())
|
|
{
|
|
case Extio.TYPE_CONSOLE:
|
|
return closeConsole (
|
|
(Console)extio.getHandle());
|
|
|
|
case Extio.TYPE_FILE:
|
|
return closeFile ((File)extio.getHandle());
|
|
|
|
case Extio.TYPE_PIPE:
|
|
return closePipe ((Pipe)extio.getHandle());
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
protected int readExtio (Extio extio, char[] buf, int len)
|
|
{
|
|
// this check is needed because 0 is used to indicate
|
|
// the end of the stream. java streams can return 0
|
|
// if the data given is 0 bytes and it didn't reach
|
|
// the end of the stream.
|
|
if (len <= 0) return -1;
|
|
|
|
switch (extio.getType())
|
|
{
|
|
|
|
case Extio.TYPE_CONSOLE:
|
|
{
|
|
return readConsole (
|
|
(Console)extio.getHandle(), buf, len);
|
|
}
|
|
|
|
case Extio.TYPE_FILE:
|
|
{
|
|
return readFile (
|
|
(File)extio.getHandle(), buf, len);
|
|
}
|
|
|
|
case Extio.TYPE_PIPE:
|
|
{
|
|
return readPipe (
|
|
(Pipe)extio.getHandle(), buf, len);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
protected int writeExtio (Extio extio, char[] buf, int len)
|
|
{
|
|
if (len <= 0) return -1;
|
|
|
|
switch (extio.getType())
|
|
{
|
|
case Extio.TYPE_CONSOLE:
|
|
{
|
|
return writeConsole (
|
|
(Console)extio.getHandle(), buf, len);
|
|
}
|
|
|
|
case Extio.TYPE_FILE:
|
|
{
|
|
return writeFile (
|
|
(File)extio.getHandle(), buf, len);
|
|
}
|
|
|
|
case Extio.TYPE_PIPE:
|
|
{
|
|
return writePipe (
|
|
(Pipe)extio.getHandle(), buf, len);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
protected int flushExtio (Extio extio)
|
|
{
|
|
switch (extio.getType())
|
|
{
|
|
|
|
case Extio.TYPE_CONSOLE:
|
|
{
|
|
return flushConsole ((Console)extio.getHandle());
|
|
}
|
|
|
|
case Extio.TYPE_FILE:
|
|
{
|
|
return flushFile ((File)extio.getHandle());
|
|
}
|
|
|
|
case Extio.TYPE_PIPE:
|
|
{
|
|
return flushPipe ((Pipe)extio.getHandle());
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
protected int nextExtio (Extio extio)
|
|
{
|
|
int type = extio.getType ();
|
|
|
|
switch (extio.getType())
|
|
{
|
|
case Extio.TYPE_CONSOLE:
|
|
{
|
|
return nextConsole ((Console)extio.getHandle());
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
protected abstract int openConsole (Console con);
|
|
protected abstract int closeConsole (Console con);
|
|
protected abstract int readConsole (Console con, char[] buf, int len);
|
|
protected abstract int writeConsole (Console con, char[] buf, int len);
|
|
protected abstract int flushConsole (Console con);
|
|
protected abstract int nextConsole (Console con);
|
|
|
|
protected abstract int openFile (File file);
|
|
protected abstract int closeFile (File file);
|
|
protected abstract int readFile (File file, char[] buf, int len);
|
|
protected abstract int writeFile (File file, char[] buf, int len);
|
|
protected abstract int flushFile (File file);
|
|
|
|
protected abstract int openPipe (Pipe pipe);
|
|
protected abstract int closePipe (Pipe pipe);
|
|
protected abstract int readPipe (Pipe pipe, char[] buf, int len);
|
|
protected abstract int writePipe (Pipe pipe, char[] buf, int len);
|
|
protected abstract int flushPipe (Pipe pipe);
|
|
|
|
/* TODO: ...
|
|
protected void onRunStart (Context ctx) {}
|
|
protected void onRunEnd (Context ctx) {}
|
|
protected void onRunReturn (Context ctx) {}
|
|
protected void onRunStatement (Context ctx) {}
|
|
*/
|
|
}
|