001/*
002 * Copyright (c) 2002-2007, Marc Prud'hommeaux. All rights reserved.
003 *
004 * This software is distributable under the BSD license. See the terms of the
005 * BSD license in the documentation provided with this software.
006 */
007package jline;
008
009import java.io.*;
010import java.util.*;
011
012/**
013 *  An {@link InputStream} implementation that wraps a {@link ConsoleReader}.
014 *  It is useful for setting up the {@link System#in} for a generic
015 *  console.
016 *  @author  <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
017 */
018public class ConsoleReaderInputStream extends SequenceInputStream {
019    private static InputStream systemIn = System.in;
020
021    public static void setIn() throws IOException {
022        setIn(new ConsoleReader());
023    }
024
025    public static void setIn(final ConsoleReader reader) {
026        System.setIn(new ConsoleReaderInputStream(reader));
027    }
028
029    /**
030     *  Restore the original {@link System#in} input stream.
031     */
032    public static void restoreIn() {
033        System.setIn(systemIn);
034    }
035
036    public ConsoleReaderInputStream(final ConsoleReader reader) {
037        super(new ConsoleEnumeration(reader));
038    }
039
040    private static class ConsoleEnumeration implements Enumeration {
041        private final ConsoleReader reader;
042        private ConsoleLineInputStream next = null;
043        private ConsoleLineInputStream prev = null;
044
045        public ConsoleEnumeration(final ConsoleReader reader) {
046            this.reader = reader;
047        }
048
049        public Object nextElement() {
050            if (next != null) {
051                InputStream n = next;
052                prev = next;
053                next = null;
054
055                return n;
056            }
057
058            return new ConsoleLineInputStream(reader);
059        }
060
061        public boolean hasMoreElements() {
062            // the last line was null
063            if ((prev != null) && (prev.wasNull == true)) {
064                return false;
065            }
066
067            if (next == null) {
068                next = (ConsoleLineInputStream) nextElement();
069            }
070
071            return next != null;
072        }
073    }
074
075    private static class ConsoleLineInputStream extends InputStream {
076        private final ConsoleReader reader;
077        private String line = null;
078        private int index = 0;
079        private boolean eol = false;
080        protected boolean wasNull = false;
081
082        public ConsoleLineInputStream(final ConsoleReader reader) {
083            this.reader = reader;
084        }
085
086        public int read() throws IOException {
087            if (eol) {
088                return -1;
089            }
090
091            if (line == null) {
092                line = reader.readLine();
093            }
094
095            if (line == null) {
096                wasNull = true;
097                return -1;
098            }
099
100            if (index >= line.length()) {
101                eol = true;
102                return '\n'; // lines are ended with a newline
103            }
104
105            return line.charAt(index++);
106        }
107    }
108}