Package com.objfac.prebop

Source Code of com.objfac.prebop.Preprocessor

/*
* Copyright (c) 2004 Object Factory Inc. All rights reserved.
* This file is made available under the Common Public License (CPL) 1.0
* (see http://www.opensource.org/licenses/cpl.php).
* Every copy, modified or not, must retain the above copyright
* and license notices.
*/
package com.objfac.prebop;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.HashSet;

import com.objfac.prebop.ant.Filetype;

/**
* @author Bob Foster
*/
public class Preprocessor {

  private HashMap fTypeMap;
  private HashSet fCopied;
  private int fModCount;
  private int fFileCount;
  private boolean fMerge;
  private HashSet fExclude;
  private int fLno;
  private File fFile;
  private InputStream fIn;
  private static final byte[] CR = new byte[] { '\r' };
  private static final byte[] CRLF = new byte[] { '\r','\n' };
  private static final byte[] LF = new byte[] { '\n' };
  private static final String EMPTY = "";
  private int fEnd;
  private int fPos;
  private HashMap fVars;
  private byte[] fBuf;
  private byte[] fEol = CRLF;

  /**
   * Preprocess the entire indir directory and write the
   * result to the outdir directory, copying all files
   * from in to out with special handling for .java and
   * .xml files.
   */
  public int preprocess(
    String indir, String outdir,
    HashMap vars, HashSet exclude, HashMap typeMap,
    boolean replace, boolean merge)
  throws PreprocessorError {
    File indirFile = new File(indir);
    if (!indirFile.exists())
      error("Input directory "+indir+" does not exist");
    if (!indirFile.isDirectory())
      error("Input directory "+indir+" is not a directory");
    File outdirFile = new File(outdir);
    if (outdirFile.exists()) {
      if (replace)
        delete(outdirFile);
      else if (!merge)
        error("Output directory "+outdir+" already exists");
    }
    fVars = vars;
    fExclude = exclude;
    fTypeMap = typeMap;
    fMerge = merge;
    fBuf = new byte[32768];
    fFileCount = 0;
    fModCount = 0;
    fCopied = new HashSet();
    preprocess(indirFile, outdirFile);
    fCopied = null;
    fBuf = null;
    fVars = null;
    fExclude = null;
    return fFileCount;
  }
 
  public int preprocess(
    File indirFile, File outdirFile,
    HashMap vars, HashSet exclude, HashMap typeMap,
    boolean replace, boolean merge)
  throws PreprocessorError {
    //??? this doesn't catch overlapping dirs, which could lead to infinite loop
    if (indirFile.equals(outdirFile) && !merge)
      error("Input and output directories are the same");
    if (outdirFile.exists()) {
      if (replace)
        delete(outdirFile);
      else if (!merge)
        error("Output directory "+outdirFile.getAbsolutePath()+" already exists");
    }
    fVars = vars;
    fExclude = exclude;
    fTypeMap = typeMap;
    fMerge = merge;
    fBuf = new byte[32768];
    fFileCount = 0;
    fModCount = 0;
    fCopied = new HashSet();
    preprocess(indirFile, outdirFile);
    fCopied = null;
    fBuf = null;
    fVars = null;
    fExclude = null;
    return fFileCount;
  }
 
  public int preprocessFile(
    File inFile, File outFile,
    HashMap vars, HashSet exclude, HashMap typeMap,
    boolean replace, boolean merge)
  throws PreprocessorError, IOException {
    //??? this doesn't catch overlapping dirs, which could lead to infinite loop
    if (inFile.equals(outFile) && !merge)
      error("Input and output files are the same");
    if (outFile.exists()) {
      if (replace)
        delete(outFile);
      else if (!merge)
        error("Output file "+outFile.getAbsolutePath()+" already exists");
    }
    fVars = vars;
    fExclude = exclude;
    fTypeMap = typeMap;
    fMerge = merge;
    fBuf = new byte[32768];
    fFileCount = 0;
    fModCount = 0;
    fCopied = new HashSet();

    fFileCount++;
    String oldname = inFile.getCanonicalPath();
    String newname = outFile.getCanonicalPath();
    String ext = getExtension(oldname);
    Filetype ft = (Filetype) fTypeMap.get(ext);
    if (ft != null) {
      String outext = ft.getOutextension();
      newname = oldname.substring(0, oldname.length()-ext.length())+outext;
      preprocessFile(inFile, newname, ft);
    }
    if (!oldname.equals(newname))
      copyFile(inFile, oldname);
   
    fCopied = null;
    fBuf = null;
    fVars = null;
    fExclude = null;
    return fFileCount;
  }
 
  public int getModCount() {
    return fModCount;
  }

  private void delete(File file) throws PreprocessorError {
    boolean isdir = file.isDirectory();
    if (isdir) {
      File[] files = file.listFiles();
      if (files != null) {
        for (int i = 0; i < files.length; i++)
          delete(files[i]);
      }
    }
    if (file.exists() && !file.delete())
      error((isdir ? "Can't delete directory " : "Can't delete file ")+file.getAbsolutePath());
   
  }

  private void preprocess(File indirFile, File outdirFile) throws PreprocessorError {
    if (fExclude.contains(outdirFile.getName()))
      return;
    if (outdirFile.exists() ? !fMerge : !outdirFile.mkdirs())
      error("Cannot create output directory "+outdirFile.getAbsolutePath());
    File[] files = indirFile.listFiles();
    for (int i = 0; i < files.length; i++) {
      File file = files[i];
      String name = file.getName();
      if (!fExclude.contains(name)) {
        String outdirPath = outdirFile.getAbsolutePath();
        if (!outdirPath.endsWith(File.separator))
          outdirPath += File.separator;
        if (file.isDirectory()) {
          preprocess(file, new File(outdirPath+name));
        }
        else if (!fExclude.contains(name)) {
          fFileCount++;
          String oldname = outdirPath + name;
          String newname = null;
          if (!fCopied.contains(oldname)) {
            fCopied.add(oldname);
            String ext = getExtension(name);
            Filetype ft = (Filetype) fTypeMap.get(ext);
            if (ft != null) {
              String outext = ft.getOutextension();
              newname = outdirPath + name.substring(0, name.length()-ext.length())+outext;
              fCopied.add(newname);
              preprocessFile(file, newname, ft);
            }
            if (!oldname.equals(newname))
              copyFile(file, oldname);
          }
        }
      }
    }
  }

  private void preprocessFile(File file, String name, Filetype ft) throws PreprocessorError {
    String beg = ft.getCommentbegin();
    String end = " " + ft.getCommentend();
    preprocessFile(file, name, beg, beg+' ', end);
  }

  private String getExtension(String name) {
    int pos = name.lastIndexOf('.');
    if (pos >= 0)
      return name.substring(pos+1);
    return "";
  }

  private void copyFile(File file, File outFile) throws PreprocessorError {
    if (file.equals(outFile)) return;
    try {
      if (!outFile.createNewFile())
        error("Output file already exists "+outFile.getAbsolutePath());
      InputStream in = new BufferedInputStream(new FileInputStream(file));
      OutputStream out = new BufferedOutputStream(new FileOutputStream(outFile));
      int read;
      while ((read = in.read(fBuf)) >= 0) {
        if (read > 0) {
          out.write(fBuf, 0, read);
        }
      }
      in.close();
      out.close();
    } catch (FileNotFoundException e) {
      error("File not found "+file.getAbsolutePath());
    } catch (IOException e) {
      error("Error writing "+outFile.getAbsolutePath());
    }
    outFile.setLastModified(file.lastModified());
  }
 
  private static final int INCLUDE = 0;
  private static final int LOOK = 1;
  private static final int SKIP = 2;
  private static final int PUSH_SKIP = 3;

  private boolean preprocessFile(File file, String name, String commentStart, String insertBeg, String insertEnd) throws PreprocessorError {
    InputStream in;
    try {
      in = new BufferedInputStream(new FileInputStream(file));
    } catch (FileNotFoundException e) {
      return error("File not found "+file.getAbsolutePath());
    }
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    fIn = in;
    fFile = file;
    fPos = fEnd = 0;
    fLno = 0;
    boolean mod = false;
    try {
    while (true) {
      byte[] line = getLine();
      if (line == null) break;
      fLno++;
      int pos, indent;
      int indentEnd = skipWs(line, 0);
      if ((pos = match(line, commentStart, indentEnd)) > indentEnd) {
        pos = skipWs(line, pos);
      }
      int exprBeg = pos;
      if ((pos = match(line, "$if", exprBeg)) > exprBeg) {
        mod = true;
        Expression expr = new Expression(line, pos, fVars);
        int exprEnd = expr.getEnd();
        if (expr.eval()) {
          putLine(indentEnd, insertBeg, line, exprBeg, exprEnd, insertEnd, out, name);
          if (!preprocessIfBody(INCLUDE, commentStart, insertBeg, insertEnd, out, name))
            return false;
        }
        else {
          putLine(indentEnd, insertBeg, line, exprBeg, exprEnd, EMPTY, out, name);
          if (!preprocessIfBody(LOOK, commentStart, insertBeg, insertEnd, out, name))
            return false;
        }
      }
      else {
//        System.out.println(new String(line) + "|" + file.getName());
        putLine(line, out, name);
      }
    }
    } catch (PreprocessorError e) {
      if (e.getLocator() == null) {
        e.setLocator(new FileLocator(file.getAbsolutePath(), fLno));
      }
      throw e;
    } catch (Exception e) {
      throw new PreprocessorError(e);
    } finally {
      try {
        out.close();
        in.close();
      } catch (IOException e2) {
        // can't do much about it
      }
    }
    if (mod) {
      fModCount++;
      try {
        OutputStream outStream = new BufferedOutputStream(new FileOutputStream(
          new File(name)));
        byte[] contents = out.toByteArray();
        outStream.write(contents);
        outStream.close();
      } catch (FileNotFoundException e1) {
        return error("Error creating output stream for "+name);
      } catch (IOException e) {
        return error("Error writing output stream for "+name);
      }
    }
    else {
      copyFile(file, name);
    }
    return true;
  }
 
  private void copyFile(File file, String name) throws PreprocessorError {
    copyFile(file, new File(name));
  }

  private boolean preprocessIfBody(int state, String commentStart, String insertBeg, String insertEnd, OutputStream out, String name) throws PreprocessorError {
    int pos = -1;
    byte[] line;
    int indentEnd, exprBeg, exprEnd;
    while (true) {
      line = getLine();
      if (line == null) {
        return error("End of file before $endif", fLno, new byte[0], fFile);
      }
      fLno++;
      indentEnd = skipWs(line, 0);
      if ((pos = match(line, commentStart, indentEnd)) > indentEnd) {
        pos = skipWs(line, pos);
      }
      exprBeg = pos;
     
      if ((pos = match(line, "$if", exprBeg)) > exprBeg) {
        Expression expr = new Expression(line, pos, fVars);
        exprEnd = expr.getEnd();
        if (state == INCLUDE) {
          if (expr.eval()) {
            putLine(indentEnd, insertBeg, line, exprBeg, exprEnd, insertEnd, out, name);
            if (!preprocessIfBody(INCLUDE, commentStart, insertBeg, insertEnd, out, name))
              return false;
          }
          else {
            putLine(indentEnd, insertBeg, line, exprBeg, exprEnd, EMPTY, out, name);
            if (!preprocessIfBody(LOOK, commentStart, insertBeg, insertEnd, out, name))
              return false;
          }
        }
        else if (state == LOOK) {
          putLine(indentEnd, EMPTY, line, exprBeg, exprEnd, EMPTY, out, name);
          if (!preprocessIfBody(PUSH_SKIP, commentStart, insertBeg, insertEnd, out, name))
            return false;
        }
        else if (state == SKIP || state == PUSH_SKIP) {
          putLine(indentEnd, EMPTY, line, exprBeg, exprEnd, EMPTY, out, name);
          if (!preprocessIfBody(PUSH_SKIP, commentStart, insertBeg, insertEnd, out, name))
            return false;
        }
      }
      else if ((pos = match(line, "$elseif", exprBeg)) > exprBeg) {
        Expression expr = new Expression(line, pos, fVars);
        exprEnd = expr.getEnd();
        if (state == INCLUDE) {
          putLine(indentEnd, insertBeg, line, exprBeg, exprEnd, EMPTY, out, name);
          state = SKIP;
        }
        else if (state == LOOK) {
          if (expr.eval()) {
            putLine(indentEnd, EMPTY, line, exprBeg, exprEnd, insertEnd, out, name);
            state = INCLUDE;
          }
          else {
            putLine(indentEnd, EMPTY, line, exprBeg, exprEnd, EMPTY, out, name);
          }
        }
        else if (state == SKIP || state == PUSH_SKIP) {
          putLine(indentEnd, EMPTY, line, exprBeg, exprEnd, EMPTY, out, name);
        }
      }
      else if ((pos = match(line, "$else", exprBeg)) > exprBeg) {
        pos = skipWs(line, pos);
        exprEnd = match(line, "$", pos);
        if (exprEnd < 0) {
          return error("Expect $ after $else", fLno, line, fFile);
        }
        if (state == INCLUDE) {
          putLine(indentEnd, insertBeg, line, exprBeg, exprEnd, EMPTY, out, name);
          state = SKIP;
        }
        else if (state == LOOK) {
          putLine(indentEnd, EMPTY, line, exprBeg, exprEnd, insertEnd, out, name);
          state = INCLUDE;
        }
        else if (state == SKIP || state == PUSH_SKIP) {
          putLine(indentEnd, EMPTY, line, exprBeg, exprEnd, EMPTY, out, name);
        }
      }
      else if ((pos = match(line, "$endif", exprBeg)) > exprBeg) {
        pos = skipWs(line, pos);
        exprEnd = match(line, "$", pos);
        if (exprEnd < 0) {
          return error("Expect $ after $endif", fLno, line, fFile);
        }
        if (state == INCLUDE) {
          putLine(indentEnd, insertBeg, line, exprBeg, exprEnd, insertEnd, out, name);
        }
        else if (state == LOOK || state == SKIP) {
          putLine(indentEnd, EMPTY, line, exprBeg, exprEnd, insertEnd, out, name);
        }
        else if (state == PUSH_SKIP) {
          putLine(indentEnd, EMPTY, line, exprBeg, exprEnd, EMPTY, out, name);
        }
        break;
      }
      else
        putLine(line, out, name);
    }
    return true;
  }
 
  private boolean error(String msg, int lineNumber, byte[] line, File file) throws PreprocessorError {
    throw new PreprocessorError(msg, new FileLocator(file.getAbsolutePath(), lineNumber));
  }

  private boolean error(String msg) throws PreprocessorError {
    throw new PreprocessorError(msg);
  }
 
  private int match(byte[] line, String s, int pos) {
    int llen = line.length, slen = s.length();
    int i = 0, beg = pos;
    while (pos < llen && i < slen && line[pos] == s.charAt(i)) {
      pos++;
      i++;
    }
    return i == slen ? pos : beg;
  }

  private int skipWs(byte[] line, int pos) {
    while (pos < line.length && (line[pos] == ' ' || line[pos] == '\t'))
      pos++;
    return pos;
  }

  /**
   * Write line in four parts:
   *  1. line up to indentEnd.
   *  2. lineBeg.
   *  3. line between exprBeg and exprEnd.
   *  4. lineEnd.
   */
  private void putLine(int indentEnd, String lineBeg, byte[] line, int exprBeg, int exprEnd, String lineEnd, OutputStream out, String name) throws PreprocessorError {
    try {
      if (indentEnd > 0)
        out.write(line, 0, indentEnd);
      writeString(out, lineBeg);
      out.write(line, exprBeg, exprEnd-exprBeg);
      writeString(out, lineEnd);
      out.write(fEol);
    } catch (IOException e) {
      error("IO error writing "+name);
    }
  }
 
  private void writeString(OutputStream out, String s) throws IOException {
    int len = s.length();
    for (int i = 0, n = s.length(); i < n; i++) {
      out.write(0xFF&s.charAt(i));
    }
  }

  /**
   * Write line without changes.
   */
  private void putLine(byte[] line, OutputStream out, String name) throws PreprocessorError {
    try {
      out.write(line);
      out.write(fEol);
    } catch (IOException e) {
      error("IO error writing "+name);
    } catch (OutOfMemoryError e) {
      throw new OutOfMemoryError("out of memory processing file " + name);
    }
  }

  private int find(byte[] line, String target, int pos) {
    int len = line.length;
    if (pos >= len) return -1;
    int c;
    while (pos < len && ((c = line[pos]) == ' ' || c == '\t'))
      pos++;
    if (pos == len) return -1;
    int tpos = 0, tlen = target.length();
    while (pos < len && tpos < tlen && line[pos] == target.charAt(tpos)) {
      pos++;
      tpos++;
    }
    return tpos == tlen ? pos : -1;
  }

  private byte[] getLine() throws PreprocessorError {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    boolean seen = false;
    while (true) {
      int c;
      while ((c = nextChar()) >= 0 && c != '\n' && c != '\r') {
        out.write((byte)c);
        seen = true;
      }
      if (c >= 0) {
        seen = true;
        if (c == '\r') {
          if (nextChar() == '\n')
            fEol = CRLF;
          else {
            fEol = CR;
            // only push the character back on the if
            // it is not the last character in the file
            if (fPos != fEnd) {
              pushChar();
            }
          }
        }
        else
          fEol = LF;
      }
      return seen ? out.toByteArray() : null;
    }
  }
 
  private int nextChar() throws PreprocessorError {
    if (fPos == fEnd) {
      int read = 0;
      try {
        while ((read = fIn.read(fBuf)) == 0)
          continue;
      } catch (IOException e) {
        error("IO error reading "+fFile.getAbsolutePath());
      }
      if (read < 0)
        return -1;
      fEnd = read;
      fPos = 0;
    }
    return ((int) fBuf[fPos++]) & 0xFF;
  }
 
  private void pushChar() {
    fPos--;
  }

  private byte[] copySeg(byte[] seg, int segStart, int segEnd) {
    int newSegLen = segEnd-segStart, oldSegLen = seg == null ? 0 : seg.length;
    if (newSegLen > 0) {
      byte[] tmp = new byte[oldSegLen+newSegLen];
      System.arraycopy(seg,0,tmp,0,oldSegLen);
      seg = tmp;
      System.arraycopy(fBuf,segStart,seg,oldSegLen,newSegLen);
    }
    return seg;
  }

}
TOP

Related Classes of com.objfac.prebop.Preprocessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.