@@ -843,7 +843,7 @@ public void resume() {
843843 public void beforeUserCode () {
844844 synchronized (this ) {
845845 pendingBytes = null ;
846- pendingLine = null ;
846+ pendingLineCharacters = null ;
847847 }
848848 input .setState (State .BUFFER );
849849 }
@@ -977,26 +977,32 @@ public void perform(LineReaderImpl in) throws IOException {
977977 private static final Charset stdinCharset =
978978 Charset .forName (System .getProperty ("stdin.encoding" ),
979979 Charset .defaultCharset ());
980- private String pendingLine ;
981- private int pendingLinePointer ;
980+ private char [] pendingLineCharacters ;
981+ private int pendingLineCharactersPointer ;
982982 private byte [] pendingBytes ;
983983 private int pendingBytesPointer ;
984984
985985 @ Override
986986 public synchronized int readUserInput () throws IOException {
987987 if (pendingBytes == null || pendingBytes .length <= pendingBytesPointer ) {
988- char userChar = readUserInputChar ();
988+ int userCharInput = readUserInputChar ();
989+ if (userCharInput == (-1 )) {
990+ return -1 ;
991+ }
992+ char userChar = (char ) userCharInput ;
989993 StringBuilder dataToConvert = new StringBuilder ();
990994 dataToConvert .append (userChar );
991995 if (Character .isHighSurrogate (userChar )) {
992996 //surrogates cannot be converted independently,
993997 //read the low surrogate and append it to dataToConvert:
994- char lowSurrogate = readUserInputChar ();
995- if (Character .isLowSurrogate (lowSurrogate )) {
996- dataToConvert .append (lowSurrogate );
998+ int lowSurrogateInput = readUserInputChar ();
999+ if (lowSurrogateInput == (-1 )) {
1000+ //end of input, ignore at this stage
1001+ } else if (Character .isLowSurrogate ((char ) lowSurrogateInput )) {
1002+ dataToConvert .append ((char ) lowSurrogateInput );
9971003 } else {
9981004 //if not the low surrogate, rollback the reading of the character:
999- pendingLinePointer --;
1005+ pendingLineCharactersPointer --;
10001006 }
10011007 }
10021008 pendingBytes = dataToConvert .toString ().getBytes (stdinCharset );
@@ -1006,19 +1012,32 @@ public synchronized int readUserInput() throws IOException {
10061012 }
10071013
10081014 @ Override
1009- public synchronized char readUserInputChar () throws IOException {
1010- while (pendingLine == null || pendingLine .length () <= pendingLinePointer ) {
1011- pendingLine = doReadUserLine ("" , null ) + System .getProperty ("line.separator" );
1012- pendingLinePointer = 0 ;
1015+ public synchronized int readUserInputChar () throws IOException {
1016+ if (pendingLineCharacters != null && pendingLineCharacters .length == 0 ) {
1017+ return -1 ;
1018+ }
1019+ while (pendingLineCharacters == null || pendingLineCharacters .length <= pendingLineCharactersPointer ) {
1020+ String readLine = doReadUserLine ("" , null );
1021+ if (readLine == null ) {
1022+ pendingLineCharacters = new char [0 ];
1023+ return -1 ;
1024+ } else {
1025+ pendingLineCharacters = (readLine + System .getProperty ("line.separator" )).toCharArray ();
1026+ }
1027+ pendingLineCharactersPointer = 0 ;
10131028 }
1014- return pendingLine . charAt ( pendingLinePointer ++) ;
1029+ return pendingLineCharacters [ pendingLineCharactersPointer ++] ;
10151030 }
10161031
10171032 @ Override
10181033 public synchronized String readUserLine (String prompt ) throws IOException {
10191034 //TODO: correct behavior w.r.t. pre-read stuff?
1020- if (pendingLine != null && pendingLine .length () > pendingLinePointer ) {
1021- return pendingLine .substring (pendingLinePointer );
1035+ if (pendingLineCharacters != null && pendingLineCharacters .length > pendingLineCharactersPointer ) {
1036+ String result = new String (pendingLineCharacters ,
1037+ pendingLineCharactersPointer ,
1038+ pendingLineCharacters .length - pendingLineCharactersPointer );
1039+ pendingLineCharacters = null ;
1040+ return result ;
10221041 }
10231042 return doReadUserLine (prompt , null );
10241043 }
@@ -1041,6 +1060,8 @@ private synchronized String doReadUserLine(String prompt, Character mask) throws
10411060 return in .readLine (prompt .replace ("%" , "%%" ), mask );
10421061 } catch (UserInterruptException ex ) {
10431062 throw new InterruptedIOException ();
1063+ } catch (EndOfFileException ex ) {
1064+ return null ; // Signal that Ctrl+D or similar happened
10441065 } finally {
10451066 in .setParser (prevParser );
10461067 in .setHistory (prevHistory );
@@ -1051,7 +1072,11 @@ private synchronized String doReadUserLine(String prompt, Character mask) throws
10511072
10521073 public char [] readPassword (String prompt ) throws IOException {
10531074 //TODO: correct behavior w.r.t. pre-read stuff?
1054- return doReadUserLine (prompt , '\0' ).toCharArray ();
1075+ String line = doReadUserLine (prompt , '\0' );
1076+ if (line == null ) {
1077+ return null ;
1078+ }
1079+ return line .toCharArray ();
10551080 }
10561081
10571082 @ Override
0 commit comments