source: trunk/FACT++/src/Readline.cc@ 11217

Last change on this file since 11217 was 11131, checked in by tbretz, 13 years ago
Put everything into the history, but only successfull commands into the file history.
File size: 34.1 KB
Line 
1// **************************************************************************
2/** @class Readline
3
4@brief C++ wrapper for GNU's readline library
5
6This class is meant as a C++ wrapper around GNU's readline library.
7Note that because readline uses a global namespace only one instance
8of this class can exist at a time. Instantiating a second object after
9a first one was deleted might show unexpected results.
10
11When the object is instantiated readline's history is read from a file.
12At destruction the history in memory is copied back to that file.
13The history file will be truncated to fMaxLines.
14
15By overloading the Readline class the function used for auto-completion
16can be overwritten.
17
18Simple example:
19
20\code
21
22 Readline rl("MyProg"); // will read the history from "MyProg.his"
23 while (1)
24 {
25 string txt = rl.Prompt("prompt> ");
26 if (txt=="quit)
27 break;
28
29 // ... do something ...
30
31 rl.AddHistory(txt);
32 }
33
34 // On destruction the history will be written to the file
35
36\endcode
37
38Simpler example (you need to implement the Process() function)
39
40\code
41
42 Readline rl("MyProg"); // will read the history from "MyProg.his"
43 rl.Run("prompt> ");
44
45 // On destruction the history will be written to the file
46
47\endcode
48
49@section References
50
51 - <A HREF="http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html">GNU Readline</A>
52
53 */
54// **************************************************************************
55#include "Readline.h"
56
57#include <sstream>
58#include <fstream>
59#include <iostream>
60
61#include <readline/readline.h>
62#include <readline/history.h>
63
64#include <boost/filesystem.hpp>
65
66#include "tools.h"
67#include "Time.h"
68
69using namespace std;
70
71Readline *Readline::This = 0;
72
73// --------------------------------------------------------------------------
74//
75//! Construct a Readline object. The constructor reads the history from a
76//! history file. The filename is compiled by adding ".his" to the
77//! supplied argument. The name oif the history file is stored in fName.
78//!
79//! Since readline has a global namespace, the creation of only one
80//! Readline instance is allowed.
81//!
82//! The provided program name is supplied to readline by means of
83//! rl_readline_name.
84//!
85//! Readlines default callback frunction for completions is redirected
86//! to CompletionImp which in turn will call Completion, which can be
87//! overwritten by the user.
88//!
89//! Bind some default key sequences like Page-up/-down for searching forward
90//! and backward in history.
91//!
92//! @param prgname
93//! The prefix of the history filename. Usually the program name, which
94//! can be initialized by argv[0].
95//
96Readline::Readline(const char *prgname) :
97 fMaxLines(500), fLine(0), fCompletion(0)
98{
99 if (This)
100 {
101 cout << "ERROR - Readline can only be instatiated once!" << endl;
102 exit(-1);
103 }
104
105 This = this;
106
107 // Alternative completion function
108 rl_attempted_completion_function = rl_ncurses_completion_function;
109
110 // Program name
111 static const string fname = boost::filesystem::path(prgname).filename();
112 rl_readline_name = fname.c_str();
113
114 // Compile filename for history file
115 fName = string(prgname)+".his";
116
117 // Read history file
118 if (read_history(fName.c_str()))
119 cout << "WARNING - Reading " << fName << ": " << strerror(errno) << endl;
120
121 fCommandLog.open(string(prgname)+".evt");
122
123 // Setup the readline callback which are needed to redirect
124 // the otuput properly to our ncurses panel
125 rl_getc_function = rl_ncurses_getc;
126 rl_startup_hook = rl_ncurses_startup;
127 rl_redisplay_function = rl_ncurses_redisplay;
128 rl_event_hook = rl_ncurses_event_hook;
129 rl_completion_display_matches_hook = rl_ncurses_completion_display;
130
131 // Bind delete, page up, page down
132 rl_bind_keyseq("\e[3~", rl_named_function("delete-char"));
133 rl_bind_keyseq("\e[5~", rl_named_function("history-search-backward"));
134 rl_bind_keyseq("\e[6~", rl_named_function("history-search-forward"));
135 rl_bind_keyseq("\033[1;3F", rl_named_function("kill-line"));
136 rl_bind_keyseq("\033[1;5D", rl_named_function("backward-word"));
137 rl_bind_keyseq("\033[1;5C", rl_named_function("forward-word"));
138 rl_bind_key(25, rl_named_function("kill-whole-line"));
139
140 //for (int i=0; i<10; i++) cout << (int)getchar() << endl;
141}
142
143// --------------------------------------------------------------------------
144//
145//! Writes the current history to the file with the name stored in fName.
146//! In addition the written file is truncated to fMaxLines to keep the
147//! file of a reasonable size. The number of lines fMaxLines can be set
148//! by SetMaxLines before the destructor is called. Setting fMaxLines
149//! to 0 or a negative value switches automatic truncation off.
150//
151Readline::~Readline()
152{
153 // Write current history to file
154 if (write_history(fName.c_str()))
155 cout << "WARNING - Write " << fName.c_str() << ": " << strerror(errno) << endl;
156
157 // Truncate file
158 if (fMaxLines>0 && history_truncate_file(fName.c_str(), fMaxLines))
159 cout << "WARNING - Truncate " << fName.c_str() << ": " << strerror(errno) << endl;
160}
161
162// --------------------------------------------------------------------------
163//
164//! This wraps the given readline function such that the output can be
165//! redirected from thr rl_outstream to the given C++ ostream.
166//!
167//! @param out
168//! The stream to which the output should be redirected.
169//!
170//! @param function
171//! Takes a function of type bool(*)() as argument
172//!
173//! @returns
174//! The return value of the function
175//
176bool Readline::RedirectionWrapper(ostream &out, bool (*function)())
177{
178 FILE *save = SetStreamOut(tmpfile());
179 const bool rc = function();
180 FILE *file = SetStreamOut(save);
181
182 const bool empty = ftell(file)==0;
183
184 rewind(file);
185
186 if (empty)
187 {
188 out << " <empty>" << endl;
189 fclose(file);
190 return rc;
191 }
192
193 while (1)
194 {
195 const int c = getc(file);
196 if (feof(file))
197 break;
198 out << (char)c;
199 }
200 out << endl;
201
202 fclose(file);
203
204 return rc;
205}
206
207// --------------------------------------------------------------------------
208//
209//! Redirected from rl_getc_function, calls Getc
210//
211int Readline::rl_ncurses_getc(FILE *f)
212{
213 return This->Getc(f);
214}
215
216// --------------------------------------------------------------------------
217//
218//! Redirected from rl_startup_hook, calls Startup.
219//! A function called just before readline prints the first prompt.
220//
221int Readline::rl_ncurses_startup()
222{
223 This->Startup();
224 return 0; // What is this for?
225}
226
227// --------------------------------------------------------------------------
228//
229//! Redirected from rl_redisplay_function, calls Redisplay.
230//! Readline will call indirectly to update the display with the current
231//! contents of the editing buffer.
232//
233void Readline::rl_ncurses_redisplay()
234{
235 This->Redisplay();
236}
237
238// --------------------------------------------------------------------------
239//
240//! Redirected from rl_event_hook, calls Update().
241//! A function called periodically when readline is waiting for
242//! terminal input.
243//!
244int Readline::rl_ncurses_event_hook()
245{
246 This->EventHook();
247 return 0;
248}
249
250// --------------------------------------------------------------------------
251//
252//! Redirected from rl_completion_display_matches_hook,
253//! calls CompletionDisplayImp
254//!
255//! A function to be called when completing a word would normally display
256//! the list of possible matches. This function is called in lieu of
257//! Readline displaying the list. It takes three arguments:
258//! (char **matches, int num_matches, int max_length) where matches is
259//! the array of matching strings, num_matches is the number of strings
260//! in that array, and max_length is the length of the longest string in
261//! that array. Readline provides a convenience function,
262//! rl_display_match_list, that takes care of doing the display to
263//! Readline's output stream.
264//
265void Readline::rl_ncurses_completion_display(char **matches, int num, int max)
266{
267 This->CompletionDisplay(matches, num, max);
268}
269
270char **Readline::rl_ncurses_completion_function(const char *text, int start, int end)
271{
272 return This->Completion(text, start, end);
273}
274
275// --------------------------------------------------------------------------
276//
277//! Calls the default rl_getc function.
278//
279int Readline::Getc(FILE *f)
280{
281 return rl_getc(f);
282}
283
284// --------------------------------------------------------------------------
285//
286//! Default: Do nothing.
287//
288void Readline::Startup()
289{
290}
291
292// --------------------------------------------------------------------------
293//
294//! The default is to redisplay the prompt which is gotten from
295//! GetUpdatePrompt(). If GetUpdatePrompt() returns an empty string the
296//! prompt is kept untouched. This can be used to keep a prompt updated
297//! with some information (e.g. time) just by overwriting GetUpdatePrompt()
298//!
299void Readline::EventHook()
300{
301 const string p = GetUpdatePrompt();
302 if (p.empty())
303 return;
304
305 UpdatePrompt("");
306 Redisplay();
307 UpdatePrompt(p);
308 Redisplay();
309}
310
311// --------------------------------------------------------------------------
312//
313//! Called from Prompt and PromptEOF after readline has returned. It is
314//! meant as the opposite of Startup (called after readline finsihes)
315//! The default is to do nothing.
316//!
317//! @param buf
318//! A pointer to the buffer returned by readline
319//
320void Readline::Shutdown(const char *)
321{
322}
323
324// --------------------------------------------------------------------------
325//
326//! Default: call rl_redisplay()
327//
328void Readline::Redisplay()
329{
330 rl_redisplay();
331}
332
333// --------------------------------------------------------------------------
334//
335//! Default: call rl_completion_display_matches()
336//
337void Readline::CompletionDisplay(char **matches, int num, int max)
338{
339 rl_display_match_list(matches, num, max);
340}
341
342// --------------------------------------------------------------------------
343//
344//! This is a static helper for the compilation of a completion-list.
345//! It compares the two inputs (str and txt) to a maximum of the size of
346//! txt. If they match, memory is allocated with malloc and a pointer to
347//! the null-terminated version of str is returned.
348//!
349//! @param str
350//! A reference to the string which is checked (e.g. "Makefile.am")
351//!
352//! @param txt
353//! A reference to the part of the string the user has already typed,
354//! e.g. "Makef"
355//!
356//! @returns
357//! A pointer to memory allocated with malloc containing the string str
358//
359char *Readline::Compare(const string &str, const string &txt)
360{
361 /*return strncmp(str.c_str(), txt.c_str(), txt.length())==0 ? */
362 return strncasecmp(str.c_str(), txt.c_str(), txt.length())==0 ?
363 strndup(str.c_str(), str.length()) : 0;
364}
365
366char **Readline::CompletionMatches(const char *text, char *(*func)(const char*, int))
367{
368 return rl_completion_matches(text, func);
369}
370
371// --------------------------------------------------------------------------
372//
373//! The given vector should be a reference to a vector of strings
374//! containing all possible matches. The actual match-making is then
375//! done in Complete(const char *, int)
376//!
377//! The pointer fCompletion is redirected to the vector for the run time
378//! of the function, but restored afterwards. So by this you can set a
379//! default completion list in case Complete is not called or Completion
380//! not overloaded.
381//!
382//! @param v
383//! reference to a vector of strings with all possible matches
384//!
385//! @param text
386//! the text which should be matched (it is just propagated to
387//! Readline::Completion)
388//!
389char **Readline::Complete(const vector<string> &v, const char *text)
390{
391 const vector<string> *save = fCompletion;
392
393 fCompletion = &v;
394 char **rc = rl_completion_matches(const_cast<char*>(text), CompleteImp);
395 fCompletion = save;
396
397 return rc;
398}
399
400// --------------------------------------------------------------------------
401//
402//! If fCompletion==0 the default is to call readline's
403//! rl_filename_completion_function. Otherwise the contents of fCompletion
404//! are returned. To change fCompletion either initialize it via
405//! SetCompletion() (in this case you must ensure the life time of the
406//! object) or call
407//! Complete(const vector<string>&, const char*)
408//! from
409//! Completion(const char * int, int)
410//!
411//! This is the so called generator function, the readline manual says
412//! about this function:
413//!
414//! The generator function is called repeatedly from
415//! rl_completion_matches(), returning a string each time. The arguments
416//! to the generator function are text and state. text is the partial word
417//! to be completed. state is zero the first time the function is called,
418//! allowing the generator to perform any necessary initialization, and a
419//! positive non-zero integer for each subsequent call. The generator
420//! function returns (char *)NULL to inform rl_completion_matches() that
421//! there are no more possibilities left. Usually the generator function
422//! computes the list of possible completions when state is zero, and
423//! returns them one at a time on subsequent calls. Each string the
424//! generator function returns as a match must be allocated with malloc();
425//! Readline frees the strings when it has finished with them.
426//
427char *Readline::Complete(const char* text, int state)
428{
429 if (fCompletion==0)
430 return rl_filename_completion_function(text, state);
431
432 static vector<string>::const_iterator pos;
433 if (state==0)
434 pos = fCompletion->begin();
435
436 while (pos!=fCompletion->end())
437 {
438 char *rc = Compare(*pos++, text);
439 if (rc)
440 return rc;
441 }
442
443 return 0;
444}
445
446// --------------------------------------------------------------------------
447//
448//! Calls Complete()
449//
450char *Readline::CompleteImp(const char* text, int state)
451{
452 return This->Complete(text, state);
453}
454
455// --------------------------------------------------------------------------
456//
457//! The readline manual says about this function:
458//!
459//! A pointer to an alternative function to create matches. The
460//! function is called with text, start, and end. start and end are
461//! indices in rl_line_buffer saying what the boundaries of text are.
462//! If this function exists and returns NULL, or if this variable is
463//! set to NULL, then rl_complete() will call the value of
464//! rl_completion_entry_function to generate matches, otherwise the
465//! array of strings returned will be used.
466//!
467//! This function is virtual and can be overwritten. It defaults to
468//! a call to rl_completion_matches with CompleteImp as an argument
469//! which defaults to filename completion, but can also be overwritten.
470//!
471//! It is suggested that you call
472//! Complete(const vector<string>&, const char*)
473//! from here.
474//!
475//! @param text
476//! A pointer to a char array conatining the text which should be
477//! completed. The text is null-terminated.
478//!
479//! @param start
480//! The start index within readline's line buffer rl_line_buffer,
481//! at which the text starts which presumably should be completed.
482//!
483//! @param end
484//! The end index within readline's line buffer rl_line_buffer,
485//! at which the text ends which presumably should be completed.
486//!
487//! @returns
488//! An array of strings which were allocated with malloc and which
489//! will be freed by readline with the possible matches.
490//
491char **Readline::Completion(const char *text, int /*start*/, int /*end*/)
492{
493 // To do filename completion call
494 return rl_completion_matches((char*)text, CompleteImp);
495}
496
497// --------------------------------------------------------------------------
498//
499//! Adds the given string to the history buffer of readline's history by
500//! calling add_history.
501//!
502//! @param str
503//! A reference to a string which should be added to readline's
504//! history.
505//!
506//! @param skip
507//! If skip is 1 and str matches the last added entry in the history,
508//! the entry is skipped. If skip==2, all entries matching str are
509//! removed from the history before the new entry is added as last one.
510//! <skip==2 is the default>
511//
512void Readline::AddToHistory(const string &str, int skip)
513{
514 if (skip==1 && fLastLine==str)
515 return;
516
517 if (str.empty())
518 return;
519
520 int p = -1;
521 while (skip==2)
522 {
523 p = history_search_pos(str.c_str(), 0, p+1);
524 if (p<0)
525 break;
526
527 // It seems like history_search_pos works more like
528 // history_search_prefix, therefore the identity is checked again
529 const HIST_ENTRY *e = history_get(p+1);
530 if (e && str==e->line)
531 free(remove_history(p));
532 }
533
534 add_history(str.c_str());
535 fLastLine = str;
536}
537
538// --------------------------------------------------------------------------
539//
540//! @returns
541//! a string containing [{fLine}]
542//
543string Readline::GetLinePrompt() const
544{
545 ostringstream str;
546 str << '[' << fLine << ']';
547 return str.str();
548}
549
550// --------------------------------------------------------------------------
551//
552//! Calls rl_set_prompt. This can be used from readline's callback function
553//! to change the prompt while a call to the readline function is in
554//! progress.
555//!
556//! @param prompt
557//! The new prompt to be shown
558//
559void Readline::UpdatePrompt(const string &prompt) const
560{
561 rl_set_prompt(prompt.c_str());
562}
563
564// --------------------------------------------------------------------------
565//
566//! This function is used to bind a key sequence via a call to
567//! rl_bind_keyseq.
568//!
569//! Readline's manual says about this function:
570//!
571//! Bind the key sequence represented by the string keyseq to the
572//! function function, beginning in the current keymap. This makes
573//! new keymaps as necessary. The return value is non-zero if keyseq
574//! is invalid.
575//!
576//! Key sequences are escaped sequences of characters read from an input
577//! stream when a special key is pressed. This is necessary because
578//! there are usually more keys and possible combinations than ascii codes.
579//!
580//! Possible key sequences are for example:
581//! "\033OP" F1
582//! "\033[1;5A" Ctrl+up
583//! "\033[1;5B" Ctrl+down
584//! "\033[1;3A" Alt+up
585//! "\033[1;3B" Alt+down
586//! "\033[5;3~" Alt+page up
587//! "\033[6;3~" Alt+page down
588//! "\033+" Alt++
589//! "\033-" Alt+-
590//! "\033\t" Alt+tab
591//! "\033[1~" Alt+tab
592//!
593//! @param seq
594//! The key sequence to be bound
595//!
596//! @param func
597//! A function of type "int func(int, int)
598//
599void Readline::BindKeySequence(const char *seq, int (*func)(int, int))
600{
601 rl_bind_keyseq(seq, func);
602}
603
604// --------------------------------------------------------------------------
605//
606//! Calls rl_variable_dumper(1)
607//!
608//! Print the readline variable names and their current values
609//! to rl_outstream. If readable is non-zero, the list is formatted
610//! in such a way that it can be made part of an inputrc file and
611//! re-read.
612//!
613//! rl_outstream can be redirected using SetStreamOut()
614//!
615//! @returns
616//! always true
617//
618bool Readline::DumpVariables()
619{
620 rl_variable_dumper(1);
621 return true;
622}
623
624// --------------------------------------------------------------------------
625//
626//! Calls rl_function_dumper(1)
627//!
628//! Print the readline function names and the key sequences currently
629//! bound to them to rl_outstream. If readable is non-zero, the list
630//! is formatted in such a way that it can be made part of an inputrc
631//! file and re-read.
632//!
633//! rl_outstream can be redirected using SetStreamOut()
634//!
635//! @returns
636//! always true
637//
638bool Readline::DumpFunctions()
639{
640 rl_function_dumper(1);
641 return true;
642}
643
644// --------------------------------------------------------------------------
645//
646//! Calls rl_list_funmap_names()
647//!
648//! Print the names of all bindable Readline functions to rl_outstream.
649//!
650//! rl_outstream can be redirected using SetStreamOut()
651//!
652//! @returns
653//! always true
654//
655bool Readline::DumpFunmap()
656{
657 rl_list_funmap_names();
658 return true;
659}
660
661// --------------------------------------------------------------------------
662//
663//! Sets rl_outstream (the stdio stream to which Readline performs output)
664//! to the new stream.
665//!
666//! @param f
667//! The new stdio stream to which readline should perform its output
668//!
669//! @return
670//! The old stream to which readline was performing output
671//
672FILE *Readline::SetStreamOut(FILE *f)
673{
674 FILE *rc = rl_outstream;
675 rl_outstream = f;
676 return rc;
677}
678
679// --------------------------------------------------------------------------
680//
681//! Sets rl_instream (the stdio stream from which Readline reads input)
682//! to the new stream.
683//!
684//! @param f
685//! The new stdio stream from which readline should read its input
686//!
687//! @return
688//! The old stream from which readline was reading it input
689//
690FILE *Readline::SetStreamIn(FILE *f)
691{
692 FILE *rc = rl_instream;
693 rl_instream = f;
694 return rc;
695}
696
697// --------------------------------------------------------------------------
698//
699//! return rl_display_prompt (the prompt which should currently be
700//! displayed on the screen) while a readline command is in progress
701//
702string Readline::GetPrompt()
703{
704 return rl_display_prompt;
705}
706
707// --------------------------------------------------------------------------
708//
709//! return rl_line_buffer (the current input line which should currently be
710//! displayed on the screen) while a readline command is in progress
711//!
712//! The length of the current line buffer (rl_end) is available as
713//! GetLineBuffer().size()
714//!
715//! Note that after readline has returned the contents of rl_end might
716//! not reflect the correct buffer length anymore, hence, the returned buffer
717//! might be truncated.
718//
719string Readline::GetBuffer()
720{
721 return string(rl_line_buffer, rl_end);
722}
723
724// --------------------------------------------------------------------------
725//
726//! return rl_point (the current cursor position within the line buffer)
727//
728int Readline::GetCursor()
729{
730 return rl_point;
731}
732
733// --------------------------------------------------------------------------
734//
735//! return strlen(rl_display_prompt) + rl_point
736//
737int Readline::GetAbsCursor()
738{
739 return strlen(rl_display_prompt) + rl_point;
740}
741
742// --------------------------------------------------------------------------
743//
744//! return rl_end (the current total length of the line buffer)
745//! Note that after readline has returned the contents of rl_end might
746//! not reflect the correct buffer length anymore.
747//
748int Readline::GetBufferLength()
749{
750 return rl_end;
751}
752
753// --------------------------------------------------------------------------
754//
755//! return the length of the prompt plus the length of the line buffer
756//
757int Readline::GetLineLength()
758{
759 return strlen(rl_display_prompt) + rl_end;
760}
761
762// --------------------------------------------------------------------------
763//
764//! Calls: Function: void rl_resize_terminal()
765//! Update Readline's internal screen size by reading values from the kernel.
766//
767void Readline::Resize()
768{
769 rl_resize_terminal();
770}
771
772// --------------------------------------------------------------------------
773//
774//! Calls: Function: void rl_set_screen_size (int rows, int cols)
775//! Set Readline's idea of the terminal size to rows rows and cols columns.
776//!
777//! @param width
778//! Number of columns
779//!
780//! @param height
781//! Number of rows
782//
783void Readline::Resize(int width, int height)
784{
785 rl_set_screen_size(height, width);
786}
787
788// --------------------------------------------------------------------------
789//
790//! Get the number of cols readline assumes the screen size to be
791//
792int Readline::GetCols() const
793{
794 int rows, cols;
795 rl_get_screen_size(&rows, &cols);
796 return cols;
797}
798
799// --------------------------------------------------------------------------
800//
801//! Get the number of rows readline assumes the screen size to be
802//
803int Readline::GetRows() const
804{
805 int rows, cols;
806 rl_get_screen_size(&rows, &cols);
807 return rows;
808}
809
810// --------------------------------------------------------------------------
811//
812//! Return a list of pointer to the history contents
813//
814vector<const char*> Readline::GetHistory() const
815{
816 HIST_ENTRY **next = history_list();
817
818 vector<const char*> v;
819
820 for (; *next; next++)
821 v.push_back((*next)->line);
822
823 return v;
824}
825
826// --------------------------------------------------------------------------
827//
828//! Clear readline history (calls clear_history())
829//!
830//! @returns
831//! always true
832//
833bool Readline::ClearHistory()
834{
835 clear_history();
836 return true;
837}
838
839// --------------------------------------------------------------------------
840//
841//! Displays the current history on rl_outstream
842//!
843//! rl_outstream can be redirected using SetStreamOut()
844//!
845//! @returns
846//! always true
847//
848bool Readline::DumpHistory()
849{
850 HIST_ENTRY **next = history_list();
851
852 if (!next)
853 return true;
854
855 for (; *next; next++)
856 fprintf(rl_outstream, "%s\n", (*next)->line);
857
858 return true;
859}
860
861// --------------------------------------------------------------------------
862//
863//! Print the available commands. This is intended for being overwritten
864//! by deriving classes.
865//!
866//! rl_outstream can be redirected using SetStreamOut()
867//!
868//! @returns
869//! always true
870//
871//
872bool Readline::PrintCommands()
873{
874 fprintf(rl_outstream, "\n");
875 fprintf(rl_outstream, " Commands:\n");
876 fprintf(rl_outstream, " No application specific commands defined.\n");
877 fprintf(rl_outstream, "\n");
878 return true;
879}
880
881// --------------------------------------------------------------------------
882//
883//! Print a general help message. This is intended for being overwritten
884//! by deriving classes.
885//!
886//!
887//! rl_outstream can be redirected using SetStreamOut()
888//!
889//! @returns
890//! always true
891//
892//
893bool Readline::PrintGeneralHelp()
894{
895 fprintf(rl_outstream, "\n");
896 fprintf(rl_outstream, " General help:\n");
897 fprintf(rl_outstream, " h,help Print this help message\n");
898 fprintf(rl_outstream, " clear Clear history buffer\n");
899 fprintf(rl_outstream, " lh,history Dump the history buffer to the screen\n");
900 fprintf(rl_outstream, " v,variables Dump readline variables\n");
901 fprintf(rl_outstream, " f,functions Dump readline functions\n");
902 fprintf(rl_outstream, " m,funmap Dump readline funmap\n");
903 fprintf(rl_outstream, " c,commands Dump available commands\n");
904 fprintf(rl_outstream, " k,keylist Dump key bindings\n");
905 fprintf(rl_outstream, " .w n Sleep n milliseconds\n");
906 fprintf(rl_outstream, " .x filename Execute a script of commands\n");
907 fprintf(rl_outstream, " .q,quit Quit\n");
908 fprintf(rl_outstream, "\n");
909 fprintf(rl_outstream, " The command history is automatically loaded and saves to\n");
910 fprintf(rl_outstream, " and from %s.\n", GetName().c_str());
911 fprintf(rl_outstream, "\n");
912 return true;
913}
914
915// --------------------------------------------------------------------------
916//
917//! Print a help text about key bindings. This is intended for being
918//! overwritten by deriving classes.
919//!
920//!
921//! rl_outstream can be redirected using SetStreamOut()
922//!
923//! @returns
924//! always true
925//
926//
927bool Readline::PrintKeyBindings()
928{
929 fprintf(rl_outstream, "\n");
930 fprintf(rl_outstream, " Key bindings:\n");
931 fprintf(rl_outstream, " Page-up Search backward in history\n");
932 fprintf(rl_outstream, " Page-dn Search forward in history\n");
933 fprintf(rl_outstream, " Ctrl-left One word backward\n");
934 fprintf(rl_outstream, " Ctrl-right One word forward\n");
935 fprintf(rl_outstream, " Ctrl-d Quit\n");
936 fprintf(rl_outstream, " Ctrl-y Delete line\n");
937 fprintf(rl_outstream, " Alt-end/Ctrl-k Delete until the end of the line\n");
938 fprintf(rl_outstream, " F1 Toggle visibility of upper panel\n");
939 fprintf(rl_outstream, "\n");
940 fprintf(rl_outstream, " Default key-bindings are identical with your bash.\n");
941 fprintf(rl_outstream, "\n");
942 return true;
943}
944
945// --------------------------------------------------------------------------
946//
947//!
948//
949bool Readline::Process(const string &str)
950{
951 if (str.substr(0, 3)==".w ")
952 {
953 usleep(atoi(str.c_str()+3)*1000);
954 return true;
955 }
956
957 if (str.substr(0, 3)==".x ")
958 {
959 Execute(str.substr(3));
960 return true;
961 }
962
963 // ----------- Readline static -------------
964
965 if (str=="clear")
966 return ClearHistory();
967
968 if (str=="lh" || str=="history")
969 return DumpHistory();
970
971 if (str=="v" || str=="variables")
972 return DumpVariables();
973
974 if (str=="f" || str=="functions")
975 return DumpFunctions();
976
977 if (str=="m" || str=="funmap")
978 return DumpFunmap();
979
980 // ---------- Readline virtual -------------
981
982 if (str=="h" || str=="help")
983 return PrintGeneralHelp();
984
985 if (str=="c" || str=="commands")
986 return PrintCommands();
987
988 if (str=="k" || str=="keylist")
989 return PrintKeyBindings();
990
991 return false;
992}
993
994// --------------------------------------------------------------------------
995//
996//! This function is a wrapper around the call to readline. It encapsultes
997//! the return buffer into a std::string and deletes the memory allocated
998//! by readline. Furthermore, it removes leading and trailing whitespaces
999//! before return the result. The result is returned in the given
1000//! argument containing the prompt. Before the function returns Shutdown()
1001//! is called (as opposed to Startup when readline starts)
1002//!
1003//! @param str
1004//! The prompt which is to be shown by the readline libarary. it is
1005//! directly given to the call to readline. The result of the
1006//! readline call is returned in this string.
1007//!
1008//! @returns
1009//! true if the call succeeded as usual, false if EOF was detected
1010//! by the readline call.
1011//
1012bool Readline::PromptEOF(string &str)
1013{
1014 char *buf = readline(str.c_str());
1015 Shutdown(buf);
1016
1017 // Happens when EOF is encountered
1018 if (!buf)
1019 return false;
1020
1021 str = Tools::Trim(buf);
1022
1023 free(buf);
1024
1025 return true;
1026}
1027
1028// --------------------------------------------------------------------------
1029//
1030//! This function is a wrapper around the call to readline. It encapsultes
1031//! the return buffer into a std::string and deletes the memory allocated
1032//! by readline. Furthermore, it removes leading and trailing whitespaces
1033//! before return the result. Before the function returns Shutdown() is
1034//! called (as opposed to Startup when readline starts)
1035//!
1036//! @param prompt
1037//! The prompt which is to be shown by the readline libarary. it is
1038//! directly given to the call to readline.
1039//!
1040//! @returns
1041//! The result of the readline call
1042//
1043string Readline::Prompt(const string &prompt)
1044{
1045 char *buf = readline(prompt.c_str());
1046
1047 Shutdown(buf ? buf : "");
1048
1049 const string str = !buf || (rl_done && rl_pending_input==4)
1050 ? ".q" : Tools::Trim(buf);
1051
1052 free(buf);
1053
1054 return str;
1055}
1056
1057// --------------------------------------------------------------------------
1058//
1059//! Process a single line. All lines are added to the history, but only
1060//! accepted lines are written to the command log. Inthis case fLine is
1061//! increased by one.
1062//
1063void Readline::ProcessLine(const string &str)
1064{
1065 const bool rc = Process(str);
1066
1067 AddToHistory(str);
1068
1069 if (rc)
1070 return;
1071
1072 fLine++;
1073
1074 fCommandLog << str << endl;
1075}
1076
1077// --------------------------------------------------------------------------
1078//
1079//! This implements a loop over readline calls. A prompt to issue can be
1080//! given. If it is NULL, the prompt is retrieved from GetUpdatePrompt().
1081//! It is updated regularly by means of calls to GetUpdatePrompt() from
1082//! EventHook(). If Prompt() returns with "quit" or ".q" the loop is
1083//! exited. If ".qqq" is entered exit(-1) is called. In case of ".qqqqqq"
1084//! abort(). Both ways to exit the program are not recommended. Empty
1085//! inputs are ignored. After that Process() with the returned string
1086//! is called. If Process returns true the input is not counted and not
1087//! added to the history, otherwise the line counter is increased
1088//! and the input is added to the history.
1089//!
1090//! @param prompt
1091//! The prompt to be issued or NULL if GetUPdatePrompt should be used
1092//! instead.
1093//!
1094void Readline::Run(const char *prompt)
1095{
1096 fLine = 0;
1097 while (1)
1098 {
1099 // Before we start we have to make sure that the
1100 // screen looks like and is ordered like expected.
1101 const string str = Prompt(prompt?prompt:GetUpdatePrompt());
1102 if (str.empty())
1103 continue;
1104
1105 if (str=="quit" || str==".q")
1106 break;
1107
1108 if (str==".qqq")
1109 exit(-1);
1110
1111 if (str==".qqqqqq")
1112 abort();
1113
1114 ProcessLine(str);
1115 }
1116}
1117
1118// --------------------------------------------------------------------------
1119//
1120//! Executes commands read from an ascii file as they were typed in
1121//! the console. Empty lines and lines beginning with # are ignored.
1122//!
1123//! @param fname
1124//! Filename of file to read
1125//!
1126//! @returns
1127//! -1 if the file couldn't be read and the number of command for which
1128//! Process() was callled otherwise
1129//!
1130int Readline::Execute(const string &fname)
1131{
1132 if (IsStopped())
1133 return 0;
1134
1135 int rc = 0;
1136
1137 const string name = Tools::Trim(fname);
1138
1139 ifstream fin(name.c_str());
1140 if (!fin)
1141 return -1;
1142
1143 fCommandLog << "# " << Time() << " - " << name << " (START)" << endl;
1144
1145 string buffer;
1146 while (getline(fin, buffer, '\n'))
1147 {
1148 buffer = Tools::Trim(buffer);
1149 if (buffer.empty())
1150 continue;
1151
1152 rc++;
1153
1154 if (buffer=="quit" || buffer==".q")
1155 {
1156 Stop();
1157 break;
1158 }
1159
1160 ProcessLine(buffer);
1161 }
1162
1163 fCommandLog << "# " << Time() << " - " << name << " (FINISHED)" << endl;
1164
1165 return rc;
1166}
1167
1168// --------------------------------------------------------------------------
1169//
1170//! Stops the readline execution. It fakes the end of an editing by
1171//! setting rl_done to 1. To distinguish this from a normal edit,
1172//! rl_pending_input is set to EOT.
1173//!
1174void Readline::Stop()
1175{
1176 rl_done = 1;
1177 rl_pending_input = 4; // EOT (end of transmission, ctrl-d)
1178}
1179
1180// --------------------------------------------------------------------------
1181//
1182//! @returns
1183//! the status of rl_done and rl_pending_input. If rl_done==1 and
1184//! rl_pending_input==4 true is returned, false otherwise.
1185//! This can be used to check if Stop() was called. If readline is
1186//! not in operation.
1187//!
1188bool Readline::IsStopped() const
1189{
1190 return rl_done==1 && rl_pending_input==4;
1191};
Note: See TracBrowser for help on using the repository browser.