/*
* Copyright (C) 2000-2004 Stephen Ostermiller
* http://ostermiller.org/contact.pl?regarding=BTE
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* See COPYING.TXT for details.
*/
package com.Ostermiller.bte;
import java.io.*;
import java.util.*;
import java.net.*;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileFilter;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.JScrollPane;
/**
* Compliles BTE template files.
* See <a href="http://ostermiller.org/bte/">ostermiller.org/bte/</a> for
* more inforation.
* <p>
* The compiler caches the contents of all urls it encounters.
*/
public class Compiler {
private Hashtable parseCache = new Hashtable();
private URL currentlyCompiling = null;
private StringWriter warnings = new StringWriter();
/**
* Compile the contents of the given url and write
* a file with the appropriate file name.
* <p>
* The url will be cached in case it is encountered
* again in the future.
*
* @param url the URL of the a file to be compiled.
* @deprecated Does not throw IO or Compile execptions. Use compileURL(URL) instead.
*/
public void compile(URL url){
try {
compileURL (url);
} catch (Exception e){
System.err.println("Error in " + url);
System.err.println(e.getMessage());
System.err.println();
}
}
/**
* Compile the contents of the given url and write
* a file with the appropriate file name.
* <p>
* The url will be cached in case it is encountered
* again in the future.
*
* @param url the URL of the a file to be compiled.
*/
public void compileURL(URL url) throws CompileException, IOException {
compileURL(url, null);
}
/**
* Compile the contents of the given url and write
* a file with the appropriate file name.
* <p>
* The url will be cached in case it is encountered
* again in the future.
*
* @param url the URL of the a file to be compiled.
* @param warningWriter Writer to which to write error messages.
*/
public void compileURL(URL url, Writer warningWriter) throws CompileException, IOException {
try {
Hashtable includes = new Hashtable();
currentlyCompiling = url;
BTEFile btef = parseAll(url);
if (btef.output){
String outFileName = nameFile(url.getFile(), btef.fileExt);
btef = resolveToTop(btef, includes);
Writer out = new FileWriter(outFileName);
btef.print(out);
out.flush();
out.close();
}
if (warningWriter != null){
btef.printWarnings(warningWriter, btef.name, url.toString());
}
} catch (CompileException cx){
throw new CompileException(cx.getMessage() + System.getProperty("line.separator") + "while compiling " + url);
}
}
private void compileDir(File f) throws CompileException, IOException {
compileDir(f, null);
}
private void compileDir(File f, Writer warningWriter) throws CompileException, IOException {
// compiles all bte files in directory (recursive)
File[] flist = f.listFiles(ioFileFilter);
for(int i=0; i<flist.length; i++){
if (flist[i].canRead() && flist[i].isDirectory()){
compileDir(flist[i], warningWriter);
} else {
compileURL(flist[i].toURL(), warningWriter);
}
}
}
/**
* Returns a description of any warnings that happened during
* compiles since the last time this method was called.
*
* @return warning messages
*/
public String getWarnings(){
String w = warnings.toString();
warnings = new StringWriter();
return w;
}
/**
* Compile data to and from the given streams.
* <p>
* All urls encountered during the compile process
* will be cached.
*
* @param in stream from which to read the file to be compiled.
* @param out stream to which to write the compiled result.
*/
public void compile(Reader in, Writer out) throws CompileException, IOException {
compile(null, in, out, null);
}
/**
* Compile data to and from the given streams.
* <p>
* All urls encountered during the compile process
* will be cached.
*
* @param name String to use in warning messages.
* @param in stream from which to read the file to be compiled.
* @param out stream to which to write the compiled result.
*/
public void compile(String name, Reader in, Writer out) throws CompileException, IOException {
compile(name, in, out, null);
}
/**
* Compile data to and from the given streams.
* <p>
* All urls encountered during the compile process
* will be cached.
* <p>
* This method does not flush or close the writers,
* the caller of this method may wish to do so.
*
* @param in stream from which to read the file to be compiled.
* @param out stream to which to write the compiled result.
* @param warningWriter place to which warnings are written.
*/
public void compile(Reader in, Writer out, Writer warningWriter) throws CompileException, IOException {
compile(null, in, out, warningWriter);
}
/**
* Compile data to and from the given streams.
* <p>
* All urls encountered during the compile process
* will be cached.
* <p>
* This method does not flush or close the writers,
* the caller of this method may wish to do so.
*
* @param name String to use in warning messages.
* @param in stream from which to read the file to be compiled.
* @param out stream to which to write the compiled result.
* @param warningWriter place to which warnings are written.
*/
public void compile(String name, Reader in, Writer out, Writer warningWriter) throws CompileException, IOException {
Hashtable includes = new Hashtable();
BTEFile btef;
try {
btef = (BTEFile)(((new parser(new Lexer(in))).parse()).value);
} catch (Exception x){
throw new CompileException(x.getMessage());
}
if (btef.parent != null){
btef.parentURL = new URL(btef.parent);
if(!parseCache.containsKey(btef.parentURL)){
parseAll(btef.parentURL);
}
}
btef = resolveToTop(btef, includes);
btef.print(out);
if (warningWriter != null){
btef.printWarnings(warningWriter, btef.name, name);
}
}
static String nameFile(String oldFileName, String newExt){
if (newExt == null){
newExt = "html";
}
int i = oldFileName.lastIndexOf(".");
if (i == -1){
return (oldFileName + "." + newExt);
} else {
return (oldFileName.substring(0,i+1) + newExt);
}
}
private BTEFile resolveToTop(BTEFile btef, Hashtable includes) throws CompileException, IOException {
btef.resolve(btef.defaults, includes, Element.RESOLVE_WARNING, Element.RESOLVE_ERROR);
btef.printWarnings(warnings, btef.name, (currentlyCompiling==null?"":currentlyCompiling.toString()));
BTEFile parent = null;
if (btef.parent != null){
btef.hashThyself(includes);
parent = (BTEFile)parseCache.get(btef.parentURL);
if (parent != null){
try {
parent = resolveToTop(parent, includes);
} catch (Exception e){
if (e instanceof CompileException){
throw new CompileException(
"Error in " + parent.url + " while compiling " +
currentlyCompiling + System.getProperty("line.separator") +
e.getMessage()
);
} else if (e instanceof IOException){
throw new IOException(
"Error in " + parent.url + " while compiling " +
currentlyCompiling + System.getProperty("line.separator") +
e.getMessage()
);
} else {
System.err.println("Error in " + parent.url + " while compiling " + currentlyCompiling);
System.err.println(e.getMessage());
System.err.println();
}
}
} else {
throw new CompileException ("'" + btef.parentURL + "' not found in parsed file cache.");
}
}
if (parent == null){
parent = btef;
}
return parent;
}
private BTEFile parseAll(URL url) throws CompileException, IOException{
InputStream in = url.openStream();
BTEFile btef = null;
try {
btef = (BTEFile)(((new parser(new Lexer(in))).parse()).value);
parseCache.put(url, btef);
btef.url = url;
btef.name = url.getFile();
if (btef.parent != null){
btef.parentURL = new URL(url, btef.parent);
if(!parseCache.containsKey(btef.parentURL)){
parseAll(btef.parentURL);
}
}
} catch (Exception e){
if (e instanceof CompileException){
throw (CompileException)e;
} else if (e instanceof IOException){
throw (IOException)e;
} else {
System.err.println("Error in " + url + " while compiling " + currentlyCompiling);
System.err.println(e.getMessage());
System.err.println();
}
}
in.close();
return btef;
}
private static java.io.FileFilter ioFileFilter = new java.io.FileFilter(){
public boolean accept(File f){
if (f.isDirectory()){
return true;
}
return f.getName().toLowerCase().endsWith(".bte");
}
};
private static FileFilter chooserFileFilter = new javax.swing.filechooser.FileFilter(){
public boolean accept(File f){
return ioFileFilter.accept(f);
}
public String getDescription(){
return "BTE Files";
}
};
/**
* Compile each of the files given as arguments.
*
* @param args file list.
*/
public static void main(String[] args){
Compiler c = new Compiler();
for (int i=0; i<args.length; i++){
File f = new File(args[i]);
if (f.exists()){
try {
f = f.getCanonicalFile();
Writer warningWriter = new OutputStreamWriter(System.err);
if (f.isDirectory()){
c.compileDir(f, warningWriter);
} else {
c.compileURL(f.toURL(), warningWriter);
}
warningWriter.flush();
} catch (Exception e){
System.err.println("Error in " + f);
System.err.println(e.getMessage());
System.err.println();
}
} else {
System.err.println("Could not open " + args[i] + ": File does not exist.");
}
}
if (args.length == 0){
JFileChooser chooser = new JFileChooser(new File("."));
chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
chooser.setMultiSelectionEnabled(true);
chooser.setDialogTitle("Choose File to Compile");
chooser.setFileFilter(chooserFileFilter);
if(chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
File[] flist = chooser.getSelectedFiles();
if (flist != null && flist.length != 0){
try {
for (int i=0; i<flist.length; i++){
File f = flist[i].getCanonicalFile();
if (f.isDirectory()){
c.compileDir(f);
} else {
c.compileURL(f.toURL());
}
}
String warningString = c.getWarnings();
if (warningString.length() > 0){
JTextArea textarea = new JTextArea(warningString, 10, 40);
JScrollPane scrollpane = new JScrollPane(textarea);
JOptionPane.showMessageDialog(
null,
scrollpane,
"Compile Warnings",
JOptionPane.WARNING_MESSAGE
);
}
} catch (CompileException x){
JOptionPane.showMessageDialog(null, x.getMessage(), "Compile Error", JOptionPane.ERROR_MESSAGE);
} catch (IOException x){
JOptionPane.showMessageDialog(null, x.getMessage(), "Error Reading File", JOptionPane.ERROR_MESSAGE);
}
} else {
JOptionPane.showMessageDialog(null, "No file selected.", "File Not Found", JOptionPane.ERROR_MESSAGE);
}
}
System.exit(0);
}
}
}