001 /** 002 * jline - Java console input library 003 * Copyright (c) 2002,2003 Marc Prud'hommeaux mwp1@cornell.edu 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library; if not, write to the Free Software 017 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018 */ 019 package jline; 020 021 import java.io.*; 022 import java.util.*; 023 024 025 /** 026 * <p> 027 * Terminal that is used for unix platforms. Terminal initialization 028 * is handled by issuing the <code>stty</code> command against the 029 * <code>/dev/tty</code> file to disable character echoing and enable 030 * character input. All known unix systems (including 031 * Linux and Macintosh OS X) support the <code>stty</code>), so this 032 * implementation should work for an reasonable POSIX system. 033 * </p> 034 * 035 * @author <a href="mailto:mwp1@cornell.edu">Marc Prud'hommeaux</a> 036 */ 037 public class UnixTerminal 038 extends Terminal 039 { 040 private Map terminfo; 041 private int width = -1; 042 private int height = -1; 043 044 045 /** 046 * Remove line-buffered input by invoking "stty -icanon min 1" 047 * against the current terminal. 048 */ 049 public void initializeTerminal () 050 throws IOException, InterruptedException 051 { 052 // save the initial tty configuration 053 final String ttyConfig = stty ("-g"); 054 055 // sanity check 056 if (ttyConfig.length () == 0 057 || (ttyConfig.indexOf ("=") == -1 058 && ttyConfig.indexOf (":") == -1)) 059 { 060 throw new IOException ("Unrecognized stty code: " + ttyConfig); 061 } 062 063 064 // set the console to be character-buffered instead of line-buffered 065 stty ("-icanon min 1"); 066 067 // disable character echoing 068 stty ("-echo"); 069 070 // at exit, restore the original tty configuration (for JDK 1.3+) 071 try 072 { 073 Runtime.getRuntime ().addShutdownHook (new Thread () 074 { 075 public void start () 076 { 077 try 078 { 079 stty (ttyConfig); 080 } 081 catch (Exception e) 082 { 083 } 084 } 085 }); 086 } 087 catch (AbstractMethodError ame) 088 { 089 // JDK 1.3+ only method. Bummer. 090 } 091 } 092 093 094 public boolean isSupported () 095 { 096 return true; 097 } 098 099 100 public boolean getEcho () 101 { 102 return false; 103 } 104 105 106 /** 107 * Returns the value of "stty size" width param. 108 * 109 * <strong>Note</strong>: this method caches the value from the 110 * first time it is called in order to increase speed, which means 111 * that changing to size of the terminal will not be reflected 112 * in the console. 113 */ 114 public int getTerminalWidth () 115 { 116 if (width != -1) 117 return width; 118 119 int val = 80; 120 try 121 { 122 String size = stty ("size"); 123 if (size.length () != 0 && size.indexOf (" ") != -1) 124 { 125 val = Integer.parseInt ( 126 size.substring (size.indexOf (" ") + 1)); 127 } 128 } 129 catch (Exception e) 130 { 131 } 132 133 return width = val; 134 } 135 136 137 /** 138 * Returns the value of "stty size" height param. 139 * 140 * <strong>Note</strong>: this method caches the value from the 141 * first time it is called in order to increase speed, which means 142 * that changing to size of the terminal will not be reflected 143 * in the console. 144 */ 145 public int getTerminalHeight () 146 { 147 if (height != -1) 148 return height; 149 150 int val = 24; 151 152 try 153 { 154 String size = stty ("size"); 155 if (size.length () != 0 && size.indexOf (" ") != -1) 156 { 157 val = Integer.parseInt ( 158 size.substring (0, size.indexOf (" "))); 159 } 160 } 161 catch (Exception e) 162 { 163 } 164 165 return height = val; 166 } 167 168 169 /** 170 * Execute the stty command with the specified arguments 171 * against the current active terminal. 172 */ 173 private static String stty (String args) 174 throws IOException, InterruptedException 175 { 176 return exec ("stty " + args + " < /dev/tty").trim (); 177 } 178 179 180 /** 181 * Execute the specified command and return the output 182 * (both stdout and stderr). 183 */ 184 private static String exec (String cmd) 185 throws IOException, InterruptedException 186 { 187 return exec (new String [] { "sh", "-c", cmd }); 188 } 189 190 191 /** 192 * Execute the specified command and return the output 193 * (both stdout and stderr). 194 */ 195 private static String exec (String [] cmd) 196 throws IOException, InterruptedException 197 { 198 ByteArrayOutputStream bout = new ByteArrayOutputStream (); 199 200 Process p = Runtime.getRuntime ().exec (cmd); 201 int c; 202 InputStream in; 203 204 in = p.getInputStream (); 205 while ((c = in.read ()) != -1) 206 bout.write (c); 207 208 in = p.getErrorStream (); 209 while ((c = in.read ()) != -1) 210 bout.write (c); 211 212 p.waitFor (); 213 214 String result = new String (bout.toByteArray ()); 215 return result; 216 } 217 } 218