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

Last change on this file since 11045 was 11042, checked in by tbretz, 13 years ago
Added time to output in Execute
File size: 33.4 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 fCommandLog << str << endl;
952
953 if (str.substr(0, 3)==".w ")
954 {
955 usleep(atoi(str.c_str()+3)*1000);
956 return true;
957 }
958
959 if (str.substr(0, 3)==".x ")
960 {
961 Execute(str.substr(3));
962 return true;
963 }
964
965 // ----------- Readline static -------------
966
967 if (str=="clear")
968 return ClearHistory();
969
970 if (str=="lh" || str=="history")
971 return DumpHistory();
972
973 if (str=="v" || str=="variables")
974 return DumpVariables();
975
976 if (str=="f" || str=="functions")
977 return DumpFunctions();
978
979 if (str=="m" || str=="funmap")
980 return DumpFunmap();
981
982 // ---------- Readline virtual -------------
983
984 if (str=="h" || str=="help")
985 return PrintGeneralHelp();
986
987 if (str=="c" || str=="commands")
988 return PrintCommands();
989
990 if (str=="k" || str=="keylist")
991 return PrintKeyBindings();
992
993 return false;
994}
995
996// --------------------------------------------------------------------------
997//
998//! This function is a wrapper around the call to readline. It encapsultes
999//! the return buffer into a std::string and deletes the memory allocated
1000//! by readline. Furthermore, it removes leading and trailing whitespaces
1001//! before return the result. The result is returned in the given
1002//! argument containing the prompt. Before the function returns Shutdown()
1003//! is called (as opposed to Startup when readline starts)
1004//!
1005//! @param str
1006//! The prompt which is to be shown by the readline libarary. it is
1007//! directly given to the call to readline. The result of the
1008//! readline call is returned in this string.
1009//!
1010//! @returns
1011//! true if the call succeeded as usual, false if EOF was detected
1012//! by the readline call.
1013//
1014bool Readline::PromptEOF(string &str)
1015{
1016 char *buf = readline(str.c_str());
1017 Shutdown(buf);
1018
1019 // Happens when EOF is encountered
1020 if (!buf)
1021 return false;
1022
1023 str = Tools::Trim(buf);
1024
1025 free(buf);
1026
1027 return true;
1028}
1029
1030// --------------------------------------------------------------------------
1031//
1032//! This function is a wrapper around the call to readline. It encapsultes
1033//! the return buffer into a std::string and deletes the memory allocated
1034//! by readline. Furthermore, it removes leading and trailing whitespaces
1035//! before return the result. Before the function returns Shutdown() is
1036//! called (as opposed to Startup when readline starts)
1037//!
1038//! @param prompt
1039//! The prompt which is to be shown by the readline libarary. it is
1040//! directly given to the call to readline.
1041//!
1042//! @returns
1043//! The result of the readline call
1044//
1045string Readline::Prompt(const string &prompt)
1046{
1047 char *buf = readline(prompt.c_str());
1048
1049 Shutdown(buf ? buf : "");
1050
1051 const string str = !buf || (rl_done && rl_pending_input==4)
1052 ? ".q" : Tools::Trim(buf);
1053
1054 free(buf);
1055
1056 return str;
1057}
1058
1059// --------------------------------------------------------------------------
1060//
1061//! This implements a loop over readline calls. A prompt to issue can be
1062//! given. If it is NULL, the prompt is retrieved from GetUpdatePrompt().
1063//! It is updated regularly by means of calls to GetUpdatePrompt() from
1064//! EventHook(). If Prompt() returns with "quit" or ".q" the loop is
1065//! exited. If ".qqq" is entered exit(-1) is called. In case of ".qqqqqq"
1066//! abort(). Both ways to exit the program are not recommended. Empty
1067//! inputs are ignored. After that Process() with the returned string
1068//! is called. If Process returns true the input is not counted and not
1069//! added to the history, otherwise the line counter is increased
1070//! and the input is added to the history.
1071//!
1072//! @param prompt
1073//! The prompt to be issued or NULL if GetUPdatePrompt should be used
1074//! instead.
1075//!
1076void Readline::Run(const char *prompt)
1077{
1078 fLine = 0;
1079 while (1)
1080 {
1081 // Before we start we have to make sure that the
1082 // screen looks like and is ordered like expected.
1083 const string str = Prompt(prompt?prompt:GetUpdatePrompt());
1084 if (str.empty())
1085 continue;
1086
1087 if (str=="quit" || str==".q")
1088 break;
1089
1090 if (str==".qqq")
1091 exit(-1);
1092
1093 if (str==".qqqqqq")
1094 abort();
1095
1096 if (Process(str))
1097 continue;
1098
1099 fLine++;
1100
1101 AddToHistory(str);
1102 }
1103}
1104
1105// --------------------------------------------------------------------------
1106//
1107//! Executes commands read from an ascii file as they were typed in
1108//! the console. Empty lines and lines beginning with # are ignored.
1109//!
1110//! @param fname
1111//! Filename of file to read
1112//!
1113//! @returns
1114//! -1 if the file couldn't be read and the number of command for which
1115//! Process() was callled otherwise
1116//!
1117int Readline::Execute(const string &fname)
1118{
1119 int rc = 0;
1120
1121 const string name = Tools::Trim(fname);
1122
1123 ifstream fin(name.c_str());
1124 if (!fin)
1125 return -1;
1126
1127 fCommandLog << "# " << Time() << " - " << name << " (START)" << endl;
1128
1129 string buffer;
1130 while (getline(fin, buffer, '\n'))
1131 {
1132 buffer = Tools::Trim(buffer);
1133 if (buffer.empty())
1134 continue;
1135
1136 if (buffer[0]=='#')
1137 continue;
1138
1139 rc++;
1140 // FIXME: Write command log
1141 if (Process(buffer))
1142 continue;
1143
1144 fLine++;
1145
1146 AddToHistory(buffer);
1147 }
1148
1149 fCommandLog << "# " << Time() << " - " << name << " (FINISHED)" << endl;
1150
1151 return rc;
1152}
1153
1154// --------------------------------------------------------------------------
1155//
1156//! Stops the readline execution. It fakes the end of an editing by
1157//! setting rl_done to 1. To distinguish this from a normal edit,
1158//! rl_pending_input is set to EOT.
1159//!
1160void Readline::Stop()
1161{
1162 rl_done = 1;
1163 rl_pending_input = 4; // EOT (end of transmission, ctrl-d)
1164}
Note: See TracBrowser for help on using the repository browser.