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     */
007    package jline;
008    
009    import java.io.*;
010    import 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     */
018    public 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    }