1 /*
   2  * Copyright (c) 2002-2012, the original author or authors.
   3  *
   4  * This software is distributable under the BSD license. See the terms of the
   5  * BSD license in the documentation provided with this software.
   6  *
   7  * http://www.opensource.org/licenses/bsd-license.php
   8  */
   9 package jdk.internal.jline.console.internal;
  10 
  11 import jdk.internal.jline.console.ConsoleReader;
  12 
  13 import java.io.IOException;
  14 import java.io.InputStream;
  15 import java.io.SequenceInputStream;
  16 import java.util.Enumeration;
  17 
  18 // FIXME: Clean up API and move to jline.console.runner package
  19 
  20 /**
  21  * An {@link InputStream} implementation that wraps a {@link ConsoleReader}.
  22  * It is useful for setting up the {@link System#in} for a generic console.
  23  *
  24  * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a>
  25  * @since 2.7
  26  */
  27 class ConsoleReaderInputStream
  28     extends SequenceInputStream
  29 {
  30     private static InputStream systemIn = System.in;
  31 
  32     public static void setIn() throws IOException {
  33         setIn(new ConsoleReader());
  34     }
  35 
  36     public static void setIn(final ConsoleReader reader) {
  37         System.setIn(new ConsoleReaderInputStream(reader));
  38     }
  39 
  40     /**
  41      * Restore the original {@link System#in} input stream.
  42      */
  43     public static void restoreIn() {
  44         System.setIn(systemIn);
  45     }
  46 
  47     public ConsoleReaderInputStream(final ConsoleReader reader) {
  48         super(new ConsoleEnumeration(reader));
  49     }
  50 
  51     private static class ConsoleEnumeration
  52         implements Enumeration<InputStream>
  53     {
  54         private final ConsoleReader reader;
  55         private ConsoleLineInputStream next = null;
  56         private ConsoleLineInputStream prev = null;
  57 
  58         public ConsoleEnumeration(final ConsoleReader reader) {
  59             this.reader = reader;
  60         }
  61 
  62         public InputStream nextElement() {
  63             if (next != null) {
  64                 InputStream n = next;
  65                 prev = next;
  66                 next = null;
  67 
  68                 return n;
  69             }
  70 
  71             return new ConsoleLineInputStream(reader);
  72         }
  73 
  74         public boolean hasMoreElements() {
  75             // the last line was null
  76             if ((prev != null) && (prev.wasNull == true)) {
  77                 return false;
  78             }
  79 
  80             if (next == null) {
  81                 next = (ConsoleLineInputStream) nextElement();
  82             }
  83 
  84             return next != null;
  85         }
  86     }
  87 
  88     private static class ConsoleLineInputStream
  89         extends InputStream
  90     {
  91         private final ConsoleReader reader;
  92         private String line = null;
  93         private int index = 0;
  94         private boolean eol = false;
  95         protected boolean wasNull = false;
  96 
  97         public ConsoleLineInputStream(final ConsoleReader reader) {
  98             this.reader = reader;
  99         }
 100 
 101         public int read() throws IOException {
 102             if (eol) {
 103                 return -1;
 104             }
 105 
 106             if (line == null) {
 107                 line = reader.readLine();
 108             }
 109 
 110             if (line == null) {
 111                 wasNull = true;
 112                 return -1;
 113             }
 114 
 115             if (index >= line.length()) {
 116                 eol = true;
 117                 return '\n'; // lines are ended with a newline
 118             }
 119 
 120             return line.charAt(index++);
 121         }
 122     }
 123 }