blob: d75406e315e6ed4e4c13b182d00899fa23b3a716 [file] [log] [blame]
Felix Meschbergerefb2d082008-08-19 13:18:47 +00001/*
Richard S. Hall59aef192009-04-25 14:50:37 +00002 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
Felix Meschbergerefb2d082008-08-19 13:18:47 +000017package org.apache.felix.shell.remote;
18
Felix Meschbergerefb2d082008-08-19 13:18:47 +000019import java.io.IOException;
20import java.io.InputStream;
21import java.io.PrintStream;
22import java.io.Reader;
23
Felix Meschbergerefb2d082008-08-19 13:18:47 +000024/**
25 * Class implementing a terminal reader adapter
26 * originally designed for the BeanShell Interpreter.
27 * <p/>
28 * Provides simple line editing (Backspace, Strg-U and a history).
Felix Meschbergerefb2d082008-08-19 13:18:47 +000029 */
30class TerminalReader extends Reader
31{
Richard S. Hallfd9c8832010-09-20 19:28:38 +000032 protected final InputStream m_in;
33 protected final PrintStream m_out;
Richard S. Hall59aef192009-04-25 14:50:37 +000034 protected boolean m_echo = false;
35 protected boolean m_eof = false;
Felix Meschbergerefb2d082008-08-19 13:18:47 +000036
Richard S. Hall59aef192009-04-25 14:50:37 +000037 public TerminalReader(InputStream in, PrintStream out)
Felix Meschbergerefb2d082008-08-19 13:18:47 +000038 {
Richard S. Hall59aef192009-04-25 14:50:37 +000039 m_in = in;
40 m_out = out;
Felix Meschbergerefb2d082008-08-19 13:18:47 +000041 }//TerminalReader
42
Felix Meschbergerefb2d082008-08-19 13:18:47 +000043 /**
44 * Tests if this <tt>TerminalReader</tt> will echo
45 * the character input to the terminal.
46 *
47 * @return true if echo, false otherwise.
48 */
49 public boolean isEcho()
50 {
Richard S. Hall59aef192009-04-25 14:50:37 +000051 return m_echo;
Felix Meschbergerefb2d082008-08-19 13:18:47 +000052 }//isEcho
53
Felix Meschbergerefb2d082008-08-19 13:18:47 +000054 /**
55 * Sets if this <tt>TerminalReader</tt> will echo
56 * the character input to the terminal.
57 * <p/>
58 * This only makes sense in character input mode,
59 * in line mode the terminal will handle editing,
60 * and this is recommended for using a more complex shell.
61 * If you implement your own character based editor, you
62 * might as well change this.<br/>
63 * (Default is false).
64 *
65 * @param echo true if echo, false otherwise.
66 */
Richard S. Hall59aef192009-04-25 14:50:37 +000067 public void setEcho(boolean echo)
Felix Meschbergerefb2d082008-08-19 13:18:47 +000068 {
Richard S. Hall59aef192009-04-25 14:50:37 +000069 m_echo = echo;
Felix Meschbergerefb2d082008-08-19 13:18:47 +000070 }//setEcho
71
Richard S. Hall59aef192009-04-25 14:50:37 +000072 public int read(char[] chars, int off, int len) throws IOException
Felix Meschbergerefb2d082008-08-19 13:18:47 +000073 {
Richard S. Hall59aef192009-04-25 14:50:37 +000074 if (m_eof)
Felix Meschbergerefb2d082008-08-19 13:18:47 +000075 {
76 return -1;
77 }
Richard S. Hall59aef192009-04-25 14:50:37 +000078 for (int i = off; i < off + len; i++)
Felix Meschbergerefb2d082008-08-19 13:18:47 +000079 {
Richard S. Hall59aef192009-04-25 14:50:37 +000080 int ch = m_in.read();
Felix Meschbergerefb2d082008-08-19 13:18:47 +000081 //shortcut for EOT and simple EOF
Richard S. Hall59aef192009-04-25 14:50:37 +000082 if (ch == EOT || (i == off && ch == -1))
Felix Meschbergerefb2d082008-08-19 13:18:47 +000083 {
84 return -1;
85 }
Richard S. Hall59aef192009-04-25 14:50:37 +000086 chars[i] = (char) ch;
87 if (ch == -1 || ch == 10 || ch == 13)
Felix Meschbergerefb2d082008-08-19 13:18:47 +000088 {
Richard S. Hall59aef192009-04-25 14:50:37 +000089 m_eof = ch == -1; //store EOF
Felix Meschbergerefb2d082008-08-19 13:18:47 +000090 int read = i - off + 1;
Richard S. Hall59aef192009-04-25 14:50:37 +000091 if (m_echo)
Felix Meschbergerefb2d082008-08-19 13:18:47 +000092 {
Richard S. Hall59aef192009-04-25 14:50:37 +000093 m_out.write(CRLF);
Felix Meschbergerefb2d082008-08-19 13:18:47 +000094 }
95 return read;
96 }
97 //naive backspace handling
Richard S. Hall59aef192009-04-25 14:50:37 +000098 if (ch == BS || ch == DEL)
Felix Meschbergerefb2d082008-08-19 13:18:47 +000099 {
Richard S. Hall59aef192009-04-25 14:50:37 +0000100 if (i > off)
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000101 {
102 i = i - 2;
Richard S. Hall59aef192009-04-25 14:50:37 +0000103 moveLeft(1);
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000104 eraseToEndOfLine();
105 }
106 else
107 {
108 i--;
109 bell();
110 }
111 }
Richard S. Hall59aef192009-04-25 14:50:37 +0000112 else if (ch == CTRL_U)
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000113 {
Richard S. Hall59aef192009-04-25 14:50:37 +0000114 moveLeft(i - off);
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000115 eraseToEndOfLine();
116 i = off - 1;
117 }
118 else
119 {
Richard S. Hall59aef192009-04-25 14:50:37 +0000120 if (m_echo)
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000121 {
Richard S. Hall59aef192009-04-25 14:50:37 +0000122 m_out.write(chars[i]);
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000123 }
124 }
125 }
126 return len;
127 }//read
128
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000129 /**
130 * Writes the NVT BEL character to the output.
131 */
132 private void bell()
133 {
Richard S. Hall59aef192009-04-25 14:50:37 +0000134 m_out.write(BEL);
135 m_out.flush();
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000136 }//bell
137
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000138 /**
139 * Writes the standard vt100/ansi cursor moving code to the output.
140 *
141 * @param i the number of times the cursor should be moved left.
142 * @throws IOException if I/O fails.
143 */
Richard S. Hall59aef192009-04-25 14:50:37 +0000144 private void moveLeft(int i) throws IOException
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000145 {
Richard S. Hall59aef192009-04-25 14:50:37 +0000146 CURSOR_LEFT[2] = Byte.decode(Integer.toString(i)).byteValue();
147 m_out.write(CURSOR_LEFT);
148 m_out.flush();
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000149 }//moveLeft
150
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000151 /**
152 * Writes the standard vt100/ansi sequence for erasing to the end of the current line.
153 *
154 * @throws IOException if I/O fails.
155 */
156 private void eraseToEndOfLine() throws IOException
157 {
Richard S. Hall59aef192009-04-25 14:50:37 +0000158 m_out.write(ERASE_TEOL);
159 m_out.flush();
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000160 }//eraseToEndOfLine
161
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000162 /**
163 * Closes this reader.
164 * Note: will close the input, but not the output.
165 *
166 * @throws IOException
167 */
168 public void close() throws IOException
169 {
Richard S. Hall59aef192009-04-25 14:50:37 +0000170 m_in.close();
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000171 }//close
Richard S. Hallfd9c8832010-09-20 19:28:38 +0000172
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000173 /**
174 * <b>Bell</b><br>
175 * The ANSI defined byte code for the NVT bell.
176 */
177 public static final byte BEL = 7;
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000178 /**
179 * <b>BackSpace</b><br>
180 * The ANSI defined byte code of backspace.
181 */
182 public static final byte BS = 8;
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000183 /**
184 * <b>Delete</b><br>
185 * The ANSI defined byte code of delete.
186 */
187 public static final byte DEL = 127;
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000188 /**
189 * CTRL-u
190 */
191 public static final byte CTRL_U = 21;
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000192 /**
193 * Escape character.
194 */
195 private static byte ESC = 27;
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000196 /**
197 * vt100/ansi standard sequence for moving the cursor left.
198 */
199 private static byte[] CURSOR_LEFT =
Richard S. Hall59aef192009-04-25 14:50:37 +0000200 {
201 ESC, '[', '1', 'D'
202 };
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000203 /**
204 * vt100/ansi standard sequence for erasing everything from the actual cursor to
205 * the end of the current line.
206 */
207 private static byte[] ERASE_TEOL =
Richard S. Hall59aef192009-04-25 14:50:37 +0000208 {
209 ESC, '[', 'K'
210 };
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000211 /**
212 * Standard NVT line break, which HAS TO BE CR and LF.
213 */
214 private static byte[] CRLF =
Richard S. Hall59aef192009-04-25 14:50:37 +0000215 {
216 '\r', '\n'
217 };
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000218 /**
219 * Standard ASCII end of transmission.
220 */
221 private static byte EOT = 4;
Felix Meschbergerefb2d082008-08-19 13:18:47 +0000222}//class TerminalReader