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 jline.console.internal;
  10  
  11 import 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
  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 Object 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 }