0N/A/*
2362N/A * Copyright (c) 1995, 2003, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.tools.java;
0N/A
0N/Aimport java.io.IOException;
0N/Aimport java.io.InputStream;
0N/Aimport java.io.InputStreamReader;
0N/Aimport java.io.BufferedReader;
0N/Aimport java.io.FilterReader;
0N/Aimport java.io.UnsupportedEncodingException;
0N/A
0N/A/**
0N/A * An input stream for java programs. The stream treats either "\n", "\r"
0N/A * or "\r\n" as the end of a line, it always returns \n. It also parses
0N/A * UNICODE characters expressed as \uffff. However, if it sees "\\", the
0N/A * second slash cannot begin a unicode sequence. It keeps track of the current
0N/A * position in the input stream.
0N/A *
0N/A * WARNING: The contents of this source file are not part of any
0N/A * supported API. Code that depends on them does so at its own risk:
0N/A * they are subject to change or removal without notice.
0N/A *
0N/A * @author Arthur van Hoff
0N/A */
0N/A
0N/Apublic
0N/Aclass ScannerInputReader extends FilterReader implements Constants {
0N/A // A note. This class does not really properly subclass FilterReader.
0N/A // Since this class only overrides the single character read method,
0N/A // and not the multi-character read method, any use of the latter
0N/A // will not work properly. Any attempt to use this code outside of
0N/A // the compiler should take that into account.
0N/A //
0N/A // For efficiency, it might be worth moving this code to Scanner and
0N/A // getting rid of this class.
0N/A
0N/A Environment env;
0N/A long pos;
0N/A
0N/A private long chpos;
0N/A private int pushBack = -1;
0N/A
0N/A public ScannerInputReader(Environment env, InputStream in)
0N/A throws UnsupportedEncodingException
0N/A {
0N/A // ScannerInputStream has been modified to no longer use
0N/A // BufferedReader. It now does its own buffering for
0N/A // performance.
0N/A super(env.getCharacterEncoding() != null ?
0N/A new InputStreamReader(in, env.getCharacterEncoding()) :
0N/A new InputStreamReader(in));
0N/A
0N/A // Start out the buffer empty.
0N/A currentIndex = 0;
0N/A numChars = 0;
0N/A
0N/A this.env = env;
0N/A chpos = Scanner.LINEINC;
0N/A }
0N/A
0N/A //------------------------------------------------------------
0N/A // Buffering code.
0N/A
0N/A // The size of our buffer.
0N/A private static final int BUFFERLEN = 10 * 1024;
0N/A
0N/A // A character buffer.
0N/A private final char[] buffer = new char[BUFFERLEN];
0N/A
0N/A // The index of the next character to be "read" from the buffer.
0N/A private int currentIndex;
0N/A
0N/A // The number of characters in the buffer. -1 if EOF is reached.
0N/A private int numChars;
0N/A
0N/A /**
0N/A * Get the next character from our buffer.
0N/A * Note: this method has been inlined by hand in the `read' method
0N/A * below. Any changes made to this method should be equally applied
0N/A * to that code.
0N/A */
0N/A private int getNextChar() throws IOException {
0N/A // Check to see if we have either run out of characters in our
0N/A // buffer or gotten to EOF on a previous call.
0N/A if (currentIndex >= numChars) {
0N/A numChars = in.read(buffer);
0N/A if (numChars == -1) {
0N/A // We have reached EOF.
0N/A return -1;
0N/A }
0N/A
0N/A // No EOF. currentIndex points to first char in buffer.
0N/A currentIndex = 0;
0N/A }
0N/A
0N/A return buffer[currentIndex++];
0N/A }
0N/A
0N/A //------------------------------------------------------------
0N/A
0N/A public int read(char[] buffer, int off, int len) {
0N/A throw new CompilerError(
0N/A "ScannerInputReader is not a fully implemented reader.");
0N/A }
0N/A
0N/A public int read() throws IOException {
0N/A pos = chpos;
0N/A chpos += Scanner.OFFSETINC;
0N/A
0N/A int c = pushBack;
0N/A if (c == -1) {
0N/A getchar: try {
0N/A // Here the call...
0N/A // c = getNextChar();
0N/A // has been inlined by hand for performance.
0N/A
0N/A if (currentIndex >= numChars) {
0N/A numChars = in.read(buffer);
0N/A if (numChars == -1) {
0N/A // We have reached EOF.
0N/A c = -1;
0N/A break getchar;
0N/A }
0N/A
0N/A // No EOF. currentIndex points to first char in buffer.
0N/A currentIndex = 0;
0N/A }
0N/A c = buffer[currentIndex++];
0N/A
0N/A } catch (java.io.CharConversionException e) {
0N/A env.error(pos, "invalid.encoding.char");
0N/A // this is fatal error
0N/A return -1;
0N/A }
0N/A } else {
0N/A pushBack = -1;
0N/A }
0N/A
0N/A // parse special characters
0N/A switch (c) {
0N/A case -2:
0N/A // -2 is a special code indicating a pushback of a backslash that
0N/A // definitely isn't the start of a unicode sequence.
0N/A return '\\';
0N/A
0N/A case '\\':
0N/A if ((c = getNextChar()) != 'u') {
0N/A pushBack = (c == '\\' ? -2 : c);
0N/A return '\\';
0N/A }
0N/A // we have a unicode sequence
0N/A chpos += Scanner.OFFSETINC;
0N/A while ((c = getNextChar()) == 'u') {
0N/A chpos += Scanner.OFFSETINC;
0N/A }
0N/A
0N/A // unicode escape sequence
0N/A int d = 0;
0N/A for (int i = 0 ; i < 4 ; i++, chpos += Scanner.OFFSETINC, c = getNextChar()) {
0N/A switch (c) {
0N/A case '0': case '1': case '2': case '3': case '4':
0N/A case '5': case '6': case '7': case '8': case '9':
0N/A d = (d << 4) + c - '0';
0N/A break;
0N/A
0N/A case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
0N/A d = (d << 4) + 10 + c - 'a';
0N/A break;
0N/A
0N/A case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
0N/A d = (d << 4) + 10 + c - 'A';
0N/A break;
0N/A
0N/A default:
0N/A env.error(pos, "invalid.escape.char");
0N/A pushBack = c;
0N/A return d;
0N/A }
0N/A }
0N/A pushBack = c;
0N/A
0N/A // To read the following line, switch \ and /...
0N/A // Handle /u000a, /u000A, /u000d, /u000D properly as
0N/A // line terminators as per JLS 3.4, even though they are encoded
0N/A // (this properly respects the order given in JLS 3.2).
0N/A switch (d) {
0N/A case '\n':
0N/A chpos += Scanner.LINEINC;
0N/A return '\n';
0N/A case '\r':
0N/A if ((c = getNextChar()) != '\n') {
0N/A pushBack = c;
0N/A } else {
0N/A chpos += Scanner.OFFSETINC;
0N/A }
0N/A chpos += Scanner.LINEINC;
0N/A return '\n';
0N/A default:
0N/A return d;
0N/A }
0N/A
0N/A case '\n':
0N/A chpos += Scanner.LINEINC;
0N/A return '\n';
0N/A
0N/A case '\r':
0N/A if ((c = getNextChar()) != '\n') {
0N/A pushBack = c;
0N/A } else {
0N/A chpos += Scanner.OFFSETINC;
0N/A }
0N/A chpos += Scanner.LINEINC;
0N/A return '\n';
0N/A
0N/A default:
0N/A return c;
0N/A }
0N/A }
0N/A}