1: | public class In {
|
2: |
|
3: | /** End of file indicator returned by read() or peek() when no more
|
4: | characters can be read.
|
5: | */
|
6: | public static final char eof = '\uffff';
|
7: |
|
8: | private static final int empty = '\ufffe';
|
9: |
|
10: | private static final char eofChar = '\u0005'; // ctrl E
|
11: | private static InputStream in;
|
12: | private static LinkedList inputStack, bufferStack;
|
13: | private static boolean done; // true if recent operation was successful
|
14: | private static char buf; // last read character
|
15: | private static char[] LS; // line separator (eol)
|
16: |
|
17: | private static char charAfterWhiteSpace() {
|
18: | char c;
|
19: | do c = read(); while (done && c <= ' ');
|
20: | return c;
|
21: | }
|
22: |
|
23: | private static String readDigits() {
|
24: | StringBuffer b = new StringBuffer();
|
25: | char c = charAfterWhiteSpace();
|
26: | if (done && c == '-') {
|
27: | b.append(c);
|
28: | c = read();
|
29: | }
|
30: | while (done && Character.isDigit(c)) {
|
31: | b.append(c);
|
32: | c = read();
|
33: | }
|
34: | buf = c;
|
35: | return b.toString();
|
36: | }
|
37: |
|
38: | private static String readFloatDigits() {
|
39: | StringBuffer b = new StringBuffer();
|
40: | char c = charAfterWhiteSpace();
|
41: | if (done && (c == '+' || c == '-')) {
|
42: | b.append(c);
|
43: | c = read();
|
44: | }
|
45: | while (done && Character.isDigit(c)) {
|
46: | b.append(c);
|
47: | c = read();
|
48: | }
|
49: | if (done && (c == '.')) {
|
50: | b.append(c);
|
51: | c = read();
|
52: | while (done && Character.isDigit(c)) {
|
53: | b.append(c);
|
54: | c = read();
|
55: | }
|
56: | }
|
57: | if (done && (c == 'e' || c == 'E')) {
|
58: | b.append(c);
|
59: | c = read();
|
60: | if (done && (c == '+' || c == '-')) {
|
61: | b.append(c);
|
62: | c = read();
|
63: | }
|
64: | while (done && Character.isDigit(c)) {
|
65: | b.append(c);
|
66: | c = read();
|
67: | }
|
68: | }
|
69: | buf = c;
|
70: | return b.toString();
|
71: | }
|
72: |
|
73: |
|
74: | /** Read a raw character (byte).
|
75: | If an attempt is made to read beyond the end of the file,
|
76: | eof is returned and done() yields false. Otherwise the read byte
|
77: | is in the range 0..255.
|
78: | */
|
79: | public static char read() {
|
80: | char c;
|
81: | if (buf != empty) {
|
82: | c = buf;
|
83: | if (buf != eof) buf = empty;
|
84: | } else {
|
85: | try {
|
86: | c = (char)in.read();
|
87: | } catch (IOException e) {
|
88: | done = false;
|
89: | c = eof; buf = eof;
|
90: | }
|
91: | }
|
92: | if (c == eofChar && inputStack.size() == 0) { c = eof; buf = eof; }
|
93: | done = c != eof;
|
94: | return c;
|
95: | }
|
96: |
|
97: | /** Current available raw characters.
|
98: | In case of an error 0 is returned and done() yields false.
|
99: | */
|
100: | public static int available() {
|
101: | int avail;
|
102: |
|
103: | try {
|
104: | avail = in.available();
|
105: | } catch(IOException exc) {
|
106: | avail = 0;
|
107: | done = false;
|
108: | }
|
109: |
|
110: | return avail;
|
111: | }
|
112: |
|
113: | /** Read a character, but skip white spaces (byte).
|
114: | If an attempt is made to read beyond the end of the file,
|
115: | eof is returned and done() yields false. Otherwise the read byte
|
116: | is in the range 0..255.
|
117: | */
|
118: | public static char readChar() {
|
119: | return charAfterWhiteSpace();
|
120: | }
|
121: |
|
122: | /** Read a boolean value.
|
123: | This method skips white space and tries to read an identifier. If its value
|
124: | is "true" the method returns true otherwise false. If the identifier is neither
|
125: | "true" nor "false" done() yields false.
|
126: | */
|
127: | public static boolean readBoolean() {
|
128: | String s = readIdentifier();
|
129: | done = true;
|
130: | if (s.equals("true")) return true;
|
131: | else { done = s.equals("false"); return false; }
|
132: | }
|
133: |
|
134: | /** Read an identifier.
|
135: | This method skips white space and tries to read an identifier starting
|
136: | with a letter and continuing with letters or digits. If a token of this
|
137: | structure could be read, it is returned otherwise the empty string is
|
138: | returned and done() yields false.
|
139: | */
|
140: | public static String readIdentifier() {
|
141: | StringBuffer b = new StringBuffer();
|
142: | char c = charAfterWhiteSpace();
|
143: | if (done && Character.isLetter(c)) {
|
144: | b.append(c);
|
145: | c = read();
|
146: | while (done && (Character.isLetter(c) || Character.isDigit(c))) {
|
147: | b.append(c);
|
148: | c = read();
|
149: | }
|
150: | }
|
151: | buf = c;
|
152: | done = b.length() > 0;
|
153: | return b.toString();
|
154: | }
|
155: |
|
156: | /** Read a word.
|
157: | This method skips white space and tries to read a word consisting of
|
158: | all characters up to the next white space or to the end of the file.
|
159: | If a token of this structure could be read, it is returned otherwise
|
160: | an empty string is returned and done() yields false.
|
161: | */
|
162: | public static String readWord() {
|
163: | StringBuffer b = new StringBuffer();
|
164: | char c = charAfterWhiteSpace();
|
165: | while (done && c > ' ') {
|
166: | b.append(c);
|
167: | c = read();
|
168: | }
|
169: | buf = c;
|
170: | done = b.length() > 0;
|
171: | return b.toString();
|
172: | }
|
173: |
|
174: | /** Read a line of text.
|
175: | This method reads the rest of the current line (including eol) and
|
176: | returns it (excluding eol). A line may be empty.
|
177: | */
|
178: | public static String readLine() {
|
179: | StringBuffer b = new StringBuffer();
|
180: | char c = read();
|
181: | while (done && c != LS[0]) {
|
182: | b.append(c);
|
183: | c = read();
|
184: | }
|
185: |
|
186: | int i = 0;
|
187: | while (c == LS[i]) {
|
188: | ++i;
|
189: | if (i >= LS.length) { break; }
|
190: | c = read();
|
191: | }
|
192: |
|
193: | if (i < LS.length) {
|
194: | buf = c;
|
195: | } else {
|
196: | buf = empty;
|
197: | }
|
198: | if (b.length() > 0) done = true;
|
199: | return b.toString();
|
200: | }
|
201: |
|
202: | /** Read the whole file.
|
203: | This method reads from the current position to the end of the
|
204: | file and returns its text in a single large string. done() yields
|
205: | always true.
|
206: | */
|
207: | public static String readFile() {
|
208: | StringBuffer b = new StringBuffer();
|
209: | char c = charAfterWhiteSpace();
|
210: | while (done) {
|
211: | b.append(c);
|
212: | c = read();
|
213: | }
|
214: | buf = eof;
|
215: | done = true;
|
216: | return b.toString();
|
217: | }
|
218: |
|
219: | /** Read a quote-delimited string.
|
220: | This method skips white space and tries to read a string in the form "...".
|
221: | It can be used to read pieces of text that contain white space.
|
222: | */
|
223: | public static String readString() {
|
224: | StringBuffer b = new StringBuffer();
|
225: | char c = charAfterWhiteSpace();
|
226: | if (done && c == '"') {
|
227: | c = read();
|
228: | while (done && c != '"') {
|
229: | b.append(c);
|
230: | c = read();
|
231: | }
|
232: | if (c == '"') { c = read(); done = true; } else done = false;
|
233: | } else done = false;
|
234: | buf = c;
|
235: | return b.toString();
|
236: | }
|
237: |
|
238: | /** Read an integer.
|
239: | This method skips white space and tries to read an integer. If the
|
240: | text does not contain an integer or if the number is too big, the
|
241: | value 0 is returned and the subsequent call of done() yields false.
|
242: | An integer is a sequence of digits, possibly preceded by '-'.
|
243: | */
|
244: | public static int readInt() {
|
245: | String s = readDigits();
|
246: | try {
|
247: | done = true;
|
248: | return Integer.parseInt(s);
|
249: | } catch (Exception e) {
|
250: | done = false; return 0;
|
251: | }
|
252: | }
|
253: |
|
254: | /** Read a long integer.
|
255: | This method skips white space and tries to read a long integer. If the
|
256: | text does not contain a number or if the number is too big, the
|
257: | value 0 is returned and the subsequent call of done() yields false.
|
258: | A long integer is a sequence of digits, possibly preceded by '-'.
|
259: | */
|
260: | public static long readLong() {
|
261: | String s = readDigits();
|
262: | try {
|
263: | done = true;
|
264: | return Long.parseLong(s);
|
265: | } catch (Exception e) {
|
266: | done = false; return 0;
|
267: | }
|
268: | }
|
269: |
|
270: | /** Read a float value.
|
271: | This method skips white space and tries to read a float value. If the
|
272: | text does not contain a float value or if the number is not well-formed,
|
273: | the value 0f is returned and the subsequent call of done() yields false.
|
274: | An float value is as specified in the Java language description. It may
|
275: | be preceded by a '+' or a '-'.
|
276: | */
|
277: | public static float readFloat() {
|
278: | String s = readFloatDigits();
|
279: | try {
|
280: | done = true;
|
281: | return Float.parseFloat(s);
|
282: | } catch (Exception e) {
|
283: | done = false; return 0f;
|
284: | }
|
285: | }
|
286: |
|
287: | /** Read a double value.
|
288: | This method skips white space and tries to read a double value. If the
|
289: | text does not contain a double value or if the number is not well-formed,
|
290: | the value 0.0 is returned and the subsequent call of done() yields false.
|
291: | An double value is as specified in the Java language description. It may
|
292: | be preceded by a '+' or a '-'.
|
293: | */
|
294: | public static double readDouble() {
|
295: | String s = readFloatDigits();
|
296: | try {
|
297: | done = true;
|
298: | return Double.parseDouble(s);
|
299: | } catch (Exception e) {
|
300: | done = false; return 0.0;
|
301: | }
|
302: | }
|
303: |
|
304: | /** Peek at the next character.
|
305: | This method skips white space and returns the next character without removing
|
306: | it from the input stream. It can be used to find out, what token comes next
|
307: | in the input stream.
|
308: | */
|
309: | public static char peek() {
|
310: | char c = charAfterWhiteSpace();
|
311: | buf = c;
|
312: | return c;
|
313: | }
|
314: |
|
315: | /** Open a text file for reading
|
316: | The text file with the name fn is opened as the new current input
|
317: | file. When it is closed again, the previous input file is restored.
|
318: | */
|
319: | public static void open(String fn) {
|
320: | try {
|
321: | InputStream s = new FileInputStream(fn);
|
322: | bufferStack.add(new Character(buf));
|
323: | inputStack.add(in);
|
324: | in = s;
|
325: | done = true;
|
326: | } catch (FileNotFoundException e) {
|
327: | done = false;
|
328: | }
|
329: | buf = empty;
|
330: | }
|
331: |
|
332: | /** Close the current input file.
|
333: | The current input file is closed and the previous input file is
|
334: | restored. Closing the keyboard input has no effect but causes
|
335: | done() to yield false.
|
336: | */
|
337: | public static void close() {
|
338: | try {
|
339: | if (inputStack.size() > 0) {
|
340: | in.close();
|
341: | in = (InputStream) inputStack.removeLast();
|
342: | buf = ((Character) bufferStack.removeLast()).charValue();
|
343: | done = true;
|
344: | } else {
|
345: | done = false; buf = empty;
|
346: | }
|
347: | } catch (IOException e) {
|
348: | done = false; buf = empty;
|
349: | }
|
350: | }
|
351: |
|
352: | /** Check if the previous operation was successful.
|
353: | This method returns true if the previous read operation was able
|
354: | to read a token of the requested structure. It can also be called
|
355: | after open() and close() to check if these operations were successful.
|
356: | If done() is called before any other operation it yields true.
|
357: | */
|
358: | public static boolean done() {
|
359: | return done;
|
360: | }
|
361: |
|
362: | static { // initializer
|
363: | done = true;
|
364: | in = System.in;
|
365: | buf = empty;
|
366: | inputStack = new LinkedList();
|
367: | bufferStack = new LinkedList();
|
368: | LS = System.getProperty("line.separator").toCharArray();
|
369: | if (LS == null || LS.length == 0) {
|
370: | LS = new char[] { '\n' };
|
371: | }
|
372: | } |