import Jakarta.util.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.URI;
import java.util.Hashtable;
import java.util.List;
import java.util.Stack;
import java.util.EmptyStackException;
import java.util.Vector;
//**************************************************
// Executing the main of Main will perform the following:
//1) Initialization.
//2) Parse input args and remove switches and their args.
//3) Call the driver() method.
//4) Call the cleanUp() method.
//**************************************************
//
public class Main {
final static Main instance = new Main();
static private int layerID_Counter = 0;
static Vector switches = new Vector();
static Vector posArgs = new Vector();
final public static String packageName = Main.getPackageName() ;
protected List extraArgs = null ;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
// Methods to manipulate filenames as URIs:
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
public static String file2uri( String fileName ) {
URI fileURI = new File( fileName ) . toURI() . normalize() ;
String base = baseURI.getPath() ;
String path = fileURI.getPath() ;
int minSize = Math.min( base.length(), path.length() ) ;
// Find first position after a slash at which base and path differ:
//
int diff = 0 ;
while ( diff < minSize && base.charAt( diff ) == path.charAt( diff ) )
++ diff ;
diff = 1 + base.lastIndexOf( '/', diff ) ;
// Start a relative URI by first prefixing as many ".." segments
// as needed to move from base to the common parent prefix:
//
StringBuffer uri = new StringBuffer() ;
for ( int n = diff ; ( n = 1 + base.indexOf( '/', n ) ) > 0 ; )
uri.append( "../" ) ;
// Append the remaining (relative) path that leads to the file:
//
uri.append( path.substring( diff ) ) ;
return uri.toString() ;
}
public static void setBaseURI( String fileName ) {
if ( fileName == null )
fileName = "." ;
baseURI = new File( fileName ) . toURI() . normalize() ;
}
public static String uri2file( String uriName ) {
File file = new File( baseURI.resolve( uriName ) ) ;
return file.toString() ;
}
private static URI baseURI ;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
// Attribute "modelDirectory" is the base working directory as a File.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
private static File modelDirectory = null ;
/**
* Returns the base directory as a {@link File} object.
*
* @layer<kernel>
*/
public static File getModelDirectory() {
return modelDirectory ;
}
/**
* Sets the base directory to an absolute {@link File}. If
* <code>baseName</code> isn't an absolute path, it is resolved
* relative to the current working directory. If <code>baseName</code>
* is <code>null</code>, the base directory is set to the current
* working directory.
*
* @layer<kernel>
*/
public static void setModelDirectory( String baseName ) {
if ( baseName == null )
baseName = "." ;
modelDirectory = new File( baseName ) . getAbsoluteFile() ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
// Attribute "baseLayer" is derived from the base directory name.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
/**
* Returns a valid Java identifier that represents the package or
* layer name for the current file. It is derived from the base
* directory name, where non-java characters in the "path" are
* replaced with dots (".")
*
* @layer<kernel>
*/
public static String deriveLayerName() {
final char DOT = '.' ;
// Step 1: determine the relative path to the base directory:
String base = Util.getFullPath( Main.getModelDirectory() ) ;
File p = new File( kernelConstants.globals().currentAbsPath );
String path = Util.getFullPath( p.getParentFile() ) ;
if ( path.startsWith( base ) )
path = path.substring( base.length() ) ;
// Step 2: layer name by dropping illegal leading characters,
// then replacing illegal character sequences with ".":
StringBuffer layerName = new StringBuffer() ;
int index = -1 ;
while ( ++index < path.length() )
if ( Character.isJavaIdentifierStart( path.charAt( index ) ) ) {
layerName.append( path.charAt( index ) ) ;
break ;
}
boolean haveDot = false ;
while ( ++index < path.length() )
if ( Character.isJavaIdentifierPart( path.charAt( index ) ) ) {
layerName.append( path.charAt( index ) ) ;
haveDot = false ;
}
else
if ( ! haveDot ) {
layerName.append( DOT ) ;
haveDot = true ;
}
if ( haveDot )
return layerName.substring( 0, layerName.length()-1 ) ;
if ( layerName.length() < 1 ) {
AstNode.error( "can't derive layer name" ) ;
return "--unknown--" ;
}
return layerName.toString() ;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
// Attribute "packageName" is the package name of $TEqn.Main.
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //
public static String getPackageName() {
String pkg = instance.getClass().getName() ;
int period = pkg.lastIndexOf( '.' ) ;
return ( period > 0 ) ? pkg.substring( 0, period ) : "" ;
}
//**************************************************
// main
//**************************************************
static String packName = ""; // assigned below. This is the
// name of the equation file, minus the
// .equation or .equations ending
// this may be reset with a default
// in the AspectTrans layer
static public void main( String[] args ) {
ArgList arguments;
instance.initialize();
// Request layers to register their interests in switches
// and positional arguments.
instance.argInquire( 0 );
// Parse input args. Remove switches and their args.
arguments = instance.parseArgs( args );
// Extract arguments for this layer:
//
// -base specifies base directory (defaults to current directory)
//
Switch dirSwitch =
( Switch ) arguments.find( "base", Switch.class, 0 ) ;
Main.setModelDirectory( ( dirSwitch != null ) ? dirSwitch.args[0] : null ) ;
Switch packSwitch =
( Switch ) arguments.find( "a", Switch.class, 0 ) ;
String tmp = ( ( packSwitch != null ) ? packSwitch.args[0] : "" );
if ( tmp.endsWith( ".equation" ) )
tmp = tmp.substring( 0, tmp.length() - 9 );
else
if ( tmp.endsWith( ".equations" ) )
tmp = tmp.substring( 0, tmp.length() - 10 );
packName = tmp;
// reset error counter -- the counter is examined
// in cleanUp after all file arguments have been processed
Util.resetCounters();
// Call driver()
instance.driver( arguments );
// Clean up.
instance.cleanUp();
}
//**************************************************
// Parse input args. Remove switches and their args.
//**************************************************
protected ArgList parseArgs( String[] args ) {
ArgList argObjects = new ArgList();
int j,k;
Switch sw;
Switch newSwitch;
String switchName;
PositionalArg parg;
for ( int i=0; i < args.length; i++ ) {
if ( args[i].charAt( 0 ) == '-' ) {
// switch
switchName = args[i].substring( 1 );
for ( j=0; j < switches.size(); j++ ) {
sw = ( Switch ) switches.elementAt( j );
if ( switchName.compareTo( sw.name ) == 0 ) {
// Found switch. Clone it.
try {
newSwitch = ( Switch ) sw.clone();
}
catch ( CloneNotSupportedException e ) {
Util.fatalError( e );
newSwitch = null;
}
// Bind args if any
if ( sw.args != null ) {
// Allocate array to hold args
newSwitch.args = new String[sw.args.length];
// Bind args from arg list
for ( k=0; k < sw.args.length; k++ ) {
if ( ++i == args.length )
usage();
newSwitch.args[k] = args[i];
}
}
// Add newly created Switch object to argObjects.
argObjects.addElement( newSwitch );
break;
}
} // end of for loop scanning switch list
}
else {
// non-switch arg
if ( posArgs.size() > 0 ) {
parg = ( PositionalArg ) posArgs.firstElement();
posArgs.removeElementAt( 0 );
parg.binding = args[i];
// Add existing PositionalArg object to argObjects.
argObjects.addElement( parg );
}
else
if ( extraArgs != null )
extraArgs.add( args [i] ) ;
else
usage() ;
}
}
// Since we currently do not allow optional positional arguments,
// make sure all required args have been supplied.
if ( posArgs.size() != 0 )
usage();
// Print a usage message if requested:
//
if ( argObjects.find( "help", Switch.class, 0 ) != null )
usage() ;
return ( argObjects );
}
//**************************************************
// Print out usage of program.
//**************************************************
static protected void usage() {
int i, j;
Switch sw;
PositionalArg parg;
System.err.print( "Usage: " + packageName + ".Main" ) ;
// List switches
for ( i=0; i < switches.size(); i++ ) {
sw = ( Switch ) switches.elementAt( i );
if ( sw.optional )
System.err.print( " [" );
else
System.err.print( " " );
System.err.print( "-" + sw.name );
if ( sw.args != null ) {
for ( j=0; j < sw.args.length; j++ )
System.err.print( " " + sw.args[j] );
}
if ( sw.optional )
System.err.print( "]" );
}
// List positional arguments
for ( i=0; i < posArgs.size(); i++ ) {
parg = ( PositionalArg ) posArgs.elementAt( i );
System.err.print( " <" + parg.name + ">" );
}
System.err.println();
// List switch descriptions
for ( i=0; i < switches.size(); i++ ) {
sw = ( Switch ) switches.elementAt( i );
System.err.println( "\t-" + sw.name + " : " + sw.description );
}
// Force exit
System.exit( 1 ) ;
}
//**************************************************
// Initialize state prior any other processing.
//**************************************************
public void initialize() {}
//**************************************************
// Must be overridden. Each layer makes zero or more calls to
// switchRegister() and posArgRegister(). All higher-level layers then
// call Super(int).argInquire(nextLayer()); (See nextLayer() below.)
//**************************************************
//
protected void argInquire( int _layer ) {
switchRegister( new Switch( "base",
"specifies base working directory",
new String[] {"<base-working-directory>"},
true,
_layer ) ) ;
switchRegister( new Switch( "a",
"specifies name of equation file -- .equation(s) are dropped if present",
new String[] {"<equation-file>"},
true,
_layer ) ) ;
switchRegister( new Switch( "help",
"prints this helpful usage message",
null,
true,
_layer ) ) ;
}
protected final int nextLayer() {
return ( layerID_Counter++ );
}
// Services provided by top level. Cannot be overriden.
protected final void switchRegister( Switch sw ) {
switches.addElement( sw );
}
protected final void posArgRegister( PositionalArg parg ) {
posArgs.addElement( parg );
}
//**************************************************
// Can override driver() and call Super().driver() in order to
// do pre or post processing. The default driver simply calls
// createAST(), then reduceAST(), then outputAST().
// returns true if outputAST() is executed, false otherwise.
// (meaning true if file was translated).
//**************************************************
protected boolean driver( ArgList arguments ) {
AstNode ast;
ast = createAST( arguments );
if ( ast == null )
return false;
ast = reduceAST( arguments, ast );
if ( ast == null )
return false;
outputAST( arguments, ast );
return true;
}
//**************************************************
// Methods called by driver().
//**************************************************
protected AstNode createAST( ArgList argObjects ) {
return ( null );
}
protected AstNode reduceAST( ArgList argObjects,
AstNode ast ) {
return ( ast );
}
protected void outputAST( ArgList argObjects, AstNode ast ) {}
protected void cleanUp() {
// if we get to this point, there have been no fatal errors
// but there may have been errors, and their numbers may have
// accumulated if we have processed multiple files. If
// there are any errors at this time, then exit with an error
// indicator (so that composer knows something went wrong).
int nerrors = AstNode.errorCount();
if ( nerrors != 0 )
System.exit( 1 );
}
}