1 /******************************************************************************* 2 * $Revision: 1.1.1.1 $ 3 * $Date: 2004/05/10 18:48:43 $ 4 * $Author: kettenis $ 5 * 6 * Contents: A streambuf which uses the GNU readline library for line I/O 7 * (c) 2001 by Dimitris Vyzovitis [vyzo@media.mit.edu] 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public 20 * License along with this program; if not, write to the Free 21 * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 22 * MA 02111-1307 USA 23 * 24 ******************************************************************************/ 25 26 #ifndef _READLINEBUF_H_ 27 #define _READLINEBUF_H_ 28 29 #include <iostream> 30 #include <cstring> 31 #include <cassert> 32 #include <cstdlib> 33 #include <cstdio> 34 35 #include <readline/readline.h> 36 #include <readline/history.h> 37 38 #if (defined __GNUC__) && (__GNUC__ < 3) 39 #include <streambuf.h> 40 #else 41 #include <streambuf> 42 using std::streamsize; 43 using std::streambuf; 44 #endif 45 46 class readlinebuf : public streambuf { 47 public: 48 #if (defined __GNUC__) && (__GNUC__ < 3) 49 typedef char char_type; 50 typedef int int_type; 51 typedef streampos pos_type; 52 typedef streamoff off_type; 53 #endif 54 static const int_type eof = EOF; // this is -1 55 static const int_type not_eof = 0; 56 57 private: 58 const char* prompt_; 59 bool history_; 60 char* line_; 61 int low_; 62 int high_; 63 64 protected: 65 showmanyc()66 virtual int_type showmanyc() const { return high_ - low_; } 67 xsgetn(char_type * buf,streamsize n)68 virtual streamsize xsgetn( char_type* buf, streamsize n ) { 69 int rd = n > (high_ - low_)? (high_ - low_) : n; 70 memcpy( buf, line_, rd ); 71 low_ += rd; 72 73 if ( rd < n ) { 74 low_ = high_ = 0; 75 free( line_ ); // free( NULL ) is a noop 76 line_ = readline( prompt_ ); 77 if ( line_ ) { 78 high_ = strlen( line_ ); 79 if ( history_ && high_ ) add_history( line_ ); 80 rd += xsgetn( buf + rd, n - rd ); 81 } 82 } 83 84 return rd; 85 } 86 underflow()87 virtual int_type underflow() { 88 if ( high_ == low_ ) { 89 low_ = high_ = 0; 90 free( line_ ); // free( NULL ) is a noop 91 line_ = readline( prompt_ ); 92 if ( line_ ) { 93 high_ = strlen( line_ ); 94 if ( history_ && high_ ) add_history( line_ ); 95 } 96 } 97 98 if ( low_ < high_ ) return line_[low_]; 99 else return eof; 100 } 101 uflow()102 virtual int_type uflow() { 103 int_type c = underflow(); 104 if ( c != eof ) ++low_; 105 return c; 106 } 107 108 virtual int_type pbackfail( int_type c = eof ) { 109 if ( low_ > 0 ) --low_; 110 else if ( c != eof ) { 111 if ( high_ > 0 ) { 112 char* nl = (char*)realloc( line_, high_ + 1 ); 113 if ( nl ) { 114 line_ = (char*)memcpy( nl + 1, line_, high_ ); 115 high_ += 1; 116 line_[0] = char( c ); 117 } else return eof; 118 } else { 119 assert( !line_ ); 120 line_ = (char*)malloc( sizeof( char ) ); 121 *line_ = char( c ); 122 high_ = 1; 123 } 124 } else return eof; 125 126 return not_eof; 127 } 128 129 public: 130 readlinebuf( const char* prompt = NULL, bool history = true ) prompt_(prompt)131 : prompt_( prompt ), history_( history ), 132 line_( NULL ), low_( 0 ), high_( 0 ) { 133 setbuf( 0, 0 ); 134 } 135 136 137 }; 138 139 #endif 140