]> Creatis software - cpPlugins.git/blob - lib/TinyCon/Console.cxx
Moved to version 1.0
[cpPlugins.git] / lib / TinyCon / Console.cxx
1 // =========================================================================
2 // @author Leonardo Florez-Valencia (florez-l@javeriana.edu.co)
3 // =========================================================================
4
5 #include <TinyCon/Console.h>
6 #include <iostream>
7
8 // -------------------------------------------------------------------------
9 #if defined(WIN32) || defined(_WIN32) || defined(__WIN32)
10 #  include <conio.h>
11 #  include <Windows.h>
12 const char TinyCon::Console::KEY_CTRL1   = -32;
13 const char TinyCon::Console::BACKSPACE   =   8;
14 const char TinyCon::Console::UP_ARROW    =  72;
15 const char TinyCon::Console::DOWN_ARROW  =  80;
16 const char TinyCon::Console::RIGHT_ARROW =  77;
17 const char TinyCon::Console::LEFT_ARROW  =  75;
18 const char TinyCon::Console::NEWLINE     = '\r';
19
20 #else
21 #  include <termios.h>
22 #  include <unistd.h>
23 const char TinyCon::Console::KEY_CTRL1   =  17;
24 const char TinyCon::Console::BACKSPACE   = 127;
25 const char TinyCon::Console::UP_ARROW    =  65;
26 const char TinyCon::Console::DOWN_ARROW  =  66;
27 const char TinyCon::Console::RIGHT_ARROW =  67;
28 const char TinyCon::Console::LEFT_ARROW  =  68;
29 const char TinyCon::Console::NEWLINE     = '\n';
30
31 int getch( )
32 {
33   struct termios oldt, newt;
34   int ch;
35   tcgetattr( STDIN_FILENO, &oldt );
36   newt = oldt;
37   newt.c_lflag &= ~( ICANON | ECHO );
38   tcsetattr( STDIN_FILENO, TCSANOW, &newt );
39
40   ch = getchar( );
41   if( ch == TinyCon::Console::ESC )
42   {
43     ch = getchar( );
44     if( ch == 91 )
45       ch = TinyCon::Console::KEY_CTRL1;
46   }
47   tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
48   return( ch );
49 }
50 #endif // defined(WIN32) || defined(_WIN32) || defined(__WIN32)
51
52 // -------------------------------------------------------------------------
53 const unsigned long TinyCon::Console::MAX_HISTORY = 500;
54 const char TinyCon::Console::TAB =  9;
55 const char TinyCon::Console::ESC = 27;
56 const char TinyCon::Console::DEL = 51;
57 const short TinyCon::Console::M_LINE     = 0;
58 const short TinyCon::Console::M_PASSWORD = 1;
59
60 // -------------------------------------------------------------------------
61 TinyCon::Console::
62 Console( )
63 {
64   this->m_MaxHistory = Self::MAX_HISTORY;
65   this->m_Quit = false;
66   this->m_Pos = -1;
67   this->m_LinePos = 0;
68   this->m_SkipOut = false;
69 }
70
71 // -------------------------------------------------------------------------
72 TinyCon::Console::
73 Console( const std::string& prompt )
74 {
75   this->m_MaxHistory = Self::MAX_HISTORY;
76   this->m_Quit = false;
77   this->m_Prompt = prompt;
78   this->m_Pos = -1;
79   this->m_LinePos = 0;
80   this->m_SkipOut = false;
81 }
82
83 // -------------------------------------------------------------------------
84 TinyCon::Console::
85 ~Console( )
86 {
87 }
88
89 // -------------------------------------------------------------------------
90 void TinyCon::Console::
91 run( )
92 {
93   std::cout << this->m_Prompt;
94
95   bool ok = true;
96   while( ok )
97   {
98     this->m_Char = getch( );
99     if( this->hotkeys( this->m_Char ) == 0 )
100     {
101       switch( this->m_Char )
102       {
103       case Self::ESC:
104       {
105       } // end case
106       break;
107       case Self::KEY_CTRL1:
108       {
109         char c = getch( );
110         switch( c )
111         {
112         case Self::UP_ARROW:
113         {
114           if( this->m_History.size( ) > 0 )
115           {
116             if( this->m_Pos == -1 )
117             {
118               // store current command
119               this->m_Unused = "";
120               this->m_Unused.assign(
121                 this->m_Buffer.begin( ), this->m_Buffer.end( )
122                 );
123             } // end if
124
125             // clear line
126             for( int i = 0; i < this->m_LinePos; ++i )
127               std::cout << "\b \b";
128
129             // clean buffer
130             this->m_Buffer.clear( );
131
132             this->m_Pos++;
133             if( this->m_Pos > ( this->m_History.size( ) - 1 ) )
134               this->m_Pos = this->m_History.size( ) - 1;
135
136             // store in buffer
137             for( int i = 0; i < this->m_History[ this->m_Pos ].size( ); ++i )
138               this->m_Buffer.push_back( this->m_History[ this->m_Pos ][ i ] );
139             this->m_LinePos = this->m_Buffer.size( );
140             std::cout << this->m_History[ this->m_Pos ];
141           } // end if
142         } // end case
143         break;
144       case Self::DOWN_ARROW:
145         {
146           if( this->m_History.size( ) > 0 )
147           {
148             // clear line
149             for( int i = 0; i < this->m_LinePos; ++i )
150               std::cout << "\b \b";
151
152             // clean buffer
153             this->m_Buffer.clear( );
154
155             this->m_Pos--;
156             if( this->m_Pos < -1 )
157               this->m_Pos = -1;
158             if( this->m_Pos >= 0 )
159             {
160               std::cout << this->m_History[ this->m_Pos ];
161               // store in buffer
162               for( int i = 0; i < this->m_History[ this->m_Pos ].size( ); ++i )
163                 this->m_Buffer.push_back(
164                   this->m_History[ this->m_Pos ][ i ]
165                   );
166             }
167             else
168             {
169               if( this->m_Buffer.size( ) > 0 )
170               {
171                 std::cout << this->m_Unused;
172
173                 // store in buffer
174                 for( int i = 0; i < this->m_Unused.size( ); ++i )
175                   this->m_Buffer.push_back( this->m_Unused[ i ] );
176               } // end if
177             } // end if
178             this->m_LinePos = this->m_Buffer.size( );
179           } // end if
180         } // end case
181         break;
182         case Self::LEFT_ARROW:
183         {
184           // if there are characters to move left over, do so
185           if( this->m_LinePos > 0 )
186           {
187             std::cout << "\b";
188             this->m_LinePos--;
189           } // end if
190         } // end case
191         break;
192         case Self::RIGHT_ARROW:
193         {
194           // if there are characters to move right over, do so
195           if( this->m_LinePos < this->m_Buffer.size( ) )
196           {
197             std::cout << this->m_Buffer[ this->m_LinePos ];
198             this->m_LinePos++;
199           } // end if
200         } // end case
201         break;
202         case Self::DEL:
203         {
204           if( this->m_LinePos < this->m_Buffer.size( ) )
205           {
206             this->m_SkipOut = true;
207             this->m_Buffer.erase( this->m_Buffer.begin( ) + this->m_LinePos );
208             // update screen after current position
209             for( int i = this->m_LinePos; i < this->m_Buffer.size( ); ++i )
210               std::cout << this->m_Buffer[ i ];
211             // erase last char
212             std::cout << " ";
213             for( int i = this->m_LinePos; i < this->m_Buffer.size( ); ++i )
214               std::cout << "\b";
215             // make-up for erase position
216             std::cout << "\b";
217           } // end if
218         } // end case
219         break;
220         default:
221         {
222           this->m_SkipOut = true;
223         } // end case
224         break;
225         } // end switch
226       } // end case
227       break;
228       case Self::BACKSPACE:
229       {
230         if( this->m_LinePos > 0 )
231         {
232           // move cursor back, blank char, and move cursor back again
233           std::cout << "\b \b";
234           // don't forget to clean the buffer and update line position
235           if( this->m_LinePos == this->m_Buffer.size( ) )
236           {
237             this->m_Buffer.pop_back( );
238             this->m_LinePos--;
239           }
240           else
241           {
242             this->m_LinePos--;
243             this->m_Buffer.erase( this->m_Buffer.begin( ) + this->m_LinePos );
244             // update screen after current position
245             for( int i = this->m_LinePos; i < this->m_Buffer.size( ); ++i )
246               std::cout << this->m_Buffer[ i ];
247             // erase last char
248             std::cout << " ";
249             for( int i = this->m_LinePos + 1; i < this->m_Buffer.size( ); ++i )
250               std::cout << "\b";
251             // make-up for erase position and go to new position
252             std::cout << "\b\b";
253           } // end if
254         } // end if
255       } // end case
256       break;
257       case Self::TAB:
258       {
259       } // end case
260       break;
261       case Self::NEWLINE:
262       {
263         // store in string
264         this->m_String.assign(
265           this->m_Buffer.begin( ), this->m_Buffer.end( )
266           );
267
268         // save command to history
269         // trimming of command should be done in callback function
270         if( this->m_String.length( ) > 0 ) 
271           this->m_History.push_front( this->m_String );
272
273         // run command
274         std::cout << std::endl;
275         this->trigger( this->m_String );
276                                 
277         // check for exit command
278         ok = !( this->m_Quit );
279         if( ok )
280         {
281           if( this->m_History.size( ) > this->m_MaxHistory )
282             this->m_History.pop_back( );
283
284           // clean buffer
285           this->m_Buffer.clear( );
286
287           // print prompt. new line should be added from callback function
288           std::cout << this->m_Prompt;
289
290           // reset position
291           this->m_Pos = -1;
292           this->m_LinePos = 0;
293         } // end if
294       } // end case
295       break;
296       default:
297       {
298         if( !( this->m_SkipOut ) )
299         {
300           std::cout << this->m_Char;
301           if( this->m_LinePos != this->m_Buffer.size( ) )
302           {
303             // line position is not at end. Insert new char
304             this->m_Buffer.insert(
305               this->m_Buffer.begin( ) + this->m_LinePos, this->m_Char
306               );
307             // update screen after current position
308             for( int i = this->m_LinePos + 1; i < this->m_Buffer.size( ); ++i )
309               std::cout << this->m_Buffer[ i ];
310             for( int i = this->m_LinePos + 1; i < this->m_Buffer.size( ); ++i )
311               std::cout << "\b";
312           }
313           else
314             this->m_Buffer.push_back( this->m_Char );
315           this->m_LinePos++;
316         }
317         else
318           this->m_SkipOut = false;
319       } // end case
320       break;
321       } // end switch
322     } // end if
323   } // end while
324 }
325
326 // -------------------------------------------------------------------------
327 void TinyCon::Console::
328 setPrompt( const std::string& prompt )
329 {
330   this->m_Prompt = prompt;
331 }
332
333 // -------------------------------------------------------------------------
334 int TinyCon::Console::
335 trigger( const std::string& cmd )
336 {
337   return( ( this->m_Quit )? 1: 0 );
338 }
339
340 // -------------------------------------------------------------------------
341 int TinyCon::Console::
342 hotkeys( char c )
343 {
344   return( 0 );
345 }
346
347 // -------------------------------------------------------------------------
348 void TinyCon::Console::
349 pause( )
350 {
351   getch( );
352 }
353
354 // -------------------------------------------------------------------------
355 void TinyCon::Console::
356 quit( )
357 {
358   this->m_Quit = true;
359 }
360
361 // -------------------------------------------------------------------------
362 std::string TinyCon::Console::
363 getLine( )
364 {
365   return( this->getLine( Self::M_LINE, "" ) );
366 }
367
368 // -------------------------------------------------------------------------
369 std::string TinyCon::Console::
370 getLine( int mode, const std::string& delimiter )
371 {
372   std::string line;
373   char c;
374   bool ok = true;
375   while( ok )
376   {
377     c = getch( );
378     if( c == Self::NEWLINE )
379     {
380       std::cout << std::endl;
381       ok = false;
382     }
383     else if( c == Self::BACKSPACE )
384     {
385       if( line.length( ) > 0 )
386       {
387         line = line.substr( 0,line.size( ) - 1 );
388         if( mode != Self::M_PASSWORD )
389           std::cout << "\b \b";
390       } // end if
391     }
392     else
393     {
394       line += c;
395       if( mode != Self::M_PASSWORD )
396         std::cout << c;
397     } // end if
398   } // end while
399   return( line );
400 }
401
402 // -------------------------------------------------------------------------
403 void TinyCon::Console::
404 setMaxHistory( int count )
405 {
406   this->m_MaxHistory = count;
407 }
408
409 // -------------------------------------------------------------------------
410 void TinyCon::Console::
411 setBuffer( const std::string& buffer )
412 {
413   this->m_Buffer.assign( buffer.begin( ), buffer.end( ) );
414   this->m_LinePos = this->m_Buffer.size( );
415 }
416
417 // eof - $RCSfile$