diff options
Diffstat (limited to 'sources/ch/epfl/lamp/util/SourceFile.java')
-rw-r--r-- | sources/ch/epfl/lamp/util/SourceFile.java | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/sources/ch/epfl/lamp/util/SourceFile.java b/sources/ch/epfl/lamp/util/SourceFile.java new file mode 100644 index 0000000000..44dbf82506 --- /dev/null +++ b/sources/ch/epfl/lamp/util/SourceFile.java @@ -0,0 +1,217 @@ +/* ____ ____ ____ ____ ______ *\ +** / __// __ \/ __// __ \/ ____/ SOcos COmpiles Scala ** +** __\_ \/ /_/ / /__/ /_/ /\_ \ (c) 2002, LAMP/EPFL ** +** /_____/\____/\___/\____/____/ ** +\* */ + +// $Id$ + +package ch.epfl.lamp.util; + +import java.io.File; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; + +/** + * This class represents a single source file. + */ +public class SourceFile { + + //######################################################################## + // Public Constants + + /** Constants used for source parsing */ + public static final byte LF = 0x0A; + public static final byte FF = 0x0C; + public static final byte CR = 0x0D; + public static final byte SU = 0x1A; + + //######################################################################## + // Public Functions + + /** Returns the source file with the given id. */ + public static SourceFile fromId(int id) { + if (id <= 0 || files.size() < id) return UNKNOWN; + return (SourceFile)files.get(id - 1); + } + + /** Releases all source file. */ + public static void releaseAll() { + files.clear(); + } + + //######################################################################## + // Private Variables + + /** The unknown source file */ + private static final SourceFile UNKNOWN = new SourceFile(); + + /** The list containing all source files */ + private static final ArrayList files = new ArrayList(); + + //######################################################################## + // Private Fields + + /** The name of this source file */ + private final String name; + + /** The content of source this file */ + private final byte[] bytes; + + /** The id of this source file */ + private final int id; + + /** The encoding of this source file or null if unspecified */ + private String encoding; + + /** The position of the last line returned by getLine */ + private int lineNumber = 0; + private int lineStart = 0; + private int lineLength = 0; + private int nextIndex = 0; + + //######################################################################## + // Private Constructors + + /** Initializes a new instance. */ + private SourceFile() { + this.name = "<<unknown source file>>"; + this.bytes = normalize(new byte[0]); + this.id = 0; + } + + //######################################################################## + // Public Constructors + + /** Initializes a new instance. */ + public SourceFile(String name) throws IOException { + this(new File(name)); + } + + /** Initializes a new instance. */ + public SourceFile(File name) throws IOException { + this(name.toString(), read(name)); + } + + /** Initializes a new instance. */ + public SourceFile(String name, InputStream input) throws IOException { + this(name, read(name, input)); + } + + /** Initializes a new instance. */ + public SourceFile(String name, byte[] bytes) { + this.name = name; + this.bytes = normalize(bytes); + this.id = files.size() + 1; + files.add(this); + } + + //######################################################################## + // Public Methods + + /** Returns the name of this source file. */ + public String name() { + return name; + } + + /** Returns the content of this source file. */ + public byte[] bytes() { + return bytes; + } + + /** Returns the id of this source file. */ + public int id() { + return id; + } + + /** Sets the encoding of the file. */ + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** Returns the content of the given line. */ + public String getLine(int line) { + int index = lineNumber <= line ? nextIndex : (lineNumber = 0); + for (; index < bytes.length && lineNumber < line; lineNumber++) { + lineStart = index; + for (; index < bytes.length; index++) { + if (bytes[index] == CR) break; + if (bytes[index] == LF) break; + if (bytes[index] == FF) break; + } + lineLength = index - lineStart; + if (index < bytes.length) index++; + if (index < bytes.length) + if (bytes[index - 1] == CR && bytes[index] == LF) index++; + } + nextIndex = index; + try { + return encoding != null ? + new String(bytes, lineStart, lineLength, encoding) : + new String(bytes, lineStart, lineLength); + } catch (UnsupportedEncodingException exception) { + throw new Error(exception); // !!! use ApplicationError + } + } + + /** + * Returns an instance of Position representing the given line and + * column of this source file. + */ + public Position getPosition(int line, int column) { + return new Position(this, line, column); + } + + /** + * Returns the integer encoding the position of the given line and + * column of this source file. + */ + public int getEncodedPosition(int line, int column) { + return Position.encode(this, line, column); + } + + public String toString() { + return name; + } + + //######################################################################## + // Private Methods + + /** Reads the file and returns its content as a byte array. */ + private static byte[] read(File file) throws IOException { + InputStream input = new FileInputStream(file); + try { + return read(file.toString(), input); + } finally { + input.close(); + } + } + + /** Reads the InputStream and returns its content as a byte array. */ + private static byte[] read(String name, InputStream input) + throws IOException + { + try { + byte[] bytes = new byte[input.available() + 1]; + if (input.read(bytes) != bytes.length - 1) throw new IOException(); + bytes[bytes.length - 1] = SU; + return bytes; + } catch (IOException exception) { + throw new IOException("cannot read '" + name + "'"); + } + } + + /** Ensures that the last byte of the array is SU. */ + private static byte[] normalize(byte[] input) { + if (input.length > 0 && input[input.length - 1] == SU) return input; + byte[] bytes = new byte[input.length + 1]; + System.arraycopy(input, 0, bytes, 0, input.length); + bytes[input.length] = SU; + return bytes; + } + + //######################################################################## +} |