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

Last change on this file since 12392 was 11479, checked in by tbretz, 13 years ago
Replaces ato/atof by stoi/stof; replaced boost::lexical_cast by to_string
File size: 35.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//! Execute a shell command through a pipe. Write stdout to rl_outstream
864//!
865//! @param cmd
866//! Command to be executed
867//!
868//! @returns
869//! always true
870//
871bool Readline::ExecuteShellCommand(const string &cmd)
872{
873 FILE *pipe = popen(cmd.c_str(), "r");
874 if (!pipe)
875 {
876 fprintf(rl_outstream, "ERROR - Could not create pipe '%s': %m\n", cmd.c_str());
877 return true;
878 }
879
880 while (1)
881 {
882 char buf[1024];
883
884 const size_t sz = fread(buf, 1, 1024, pipe);
885
886 fwrite(buf, 1, sz, rl_outstream);
887
888 if (feof(pipe) || ferror(pipe))
889 break;
890 }
891
892 if (ferror(pipe))
893 fprintf(rl_outstream, "ERROR - Reading from pipe '%s': %m\n", cmd.c_str());
894
895 pclose(pipe);
896
897 fprintf(rl_outstream, "\n");
898
899 return true;
900}
901
902// --------------------------------------------------------------------------
903//
904//! Print the available commands. This is intended for being overwritten
905//! by deriving classes.
906//!
907//! rl_outstream can be redirected using SetStreamOut()
908//!
909//! @returns
910//! always true
911//
912//
913bool Readline::PrintCommands()
914{
915 fprintf(rl_outstream, "\n");
916 fprintf(rl_outstream, " Commands:\n");
917 fprintf(rl_outstream, " No application specific commands defined.\n");
918 fprintf(rl_outstream, "\n");
919 return true;
920}
921
922// --------------------------------------------------------------------------
923//
924//! Print a general help message. This is intended for being overwritten
925//! by deriving classes.
926//!
927//!
928//! rl_outstream can be redirected using SetStreamOut()
929//!
930//! @returns
931//! always true
932//
933//
934bool Readline::PrintGeneralHelp()
935{
936 fprintf(rl_outstream, "\n");
937 fprintf(rl_outstream, " General help:\n");
938 fprintf(rl_outstream, " h,help Print this help message\n");
939 fprintf(rl_outstream, " clear Clear history buffer\n");
940 fprintf(rl_outstream, " lh,history Dump the history buffer to the screen\n");
941 fprintf(rl_outstream, " v,variables Dump readline variables\n");
942 fprintf(rl_outstream, " f,functions Dump readline functions\n");
943 fprintf(rl_outstream, " m,funmap Dump readline funmap\n");
944 fprintf(rl_outstream, " c,commands Dump available commands\n");
945 fprintf(rl_outstream, " k,keylist Dump key bindings\n");
946 fprintf(rl_outstream, " .! command Execute a shell command\n");
947 fprintf(rl_outstream, " .w n Sleep n milliseconds\n");
948 fprintf(rl_outstream, " .x filename Execute a script of commands\n");
949 fprintf(rl_outstream, " .q,quit Quit\n");
950 fprintf(rl_outstream, "\n");
951 fprintf(rl_outstream, " The command history is automatically loaded and saves to\n");
952 fprintf(rl_outstream, " and from %s.\n", GetName().c_str());
953 fprintf(rl_outstream, "\n");
954 return true;
955}
956
957// --------------------------------------------------------------------------
958//
959//! Print a help text about key bindings. This is intended for being
960//! overwritten by deriving classes.
961//!
962//!
963//! rl_outstream can be redirected using SetStreamOut()
964//!
965//! @returns
966//! always true
967//
968//
969bool Readline::PrintKeyBindings()
970{
971 fprintf(rl_outstream, "\n");
972 fprintf(rl_outstream, " Key bindings:\n");
973 fprintf(rl_outstream, " Page-up Search backward in history\n");
974 fprintf(rl_outstream, " Page-dn Search forward in history\n");
975 fprintf(rl_outstream, " Ctrl-left One word backward\n");
976 fprintf(rl_outstream, " Ctrl-right One word forward\n");
977 fprintf(rl_outstream, " Ctrl-d Quit\n");
978 fprintf(rl_outstream, " Ctrl-y Delete line\n");
979 fprintf(rl_outstream, " Alt-end/Ctrl-k Delete until the end of the line\n");
980 fprintf(rl_outstream, " F1 Toggle visibility of upper panel\n");
981 fprintf(rl_outstream, "\n");
982 fprintf(rl_outstream, " Default key-bindings are identical with your bash.\n");
983 fprintf(rl_outstream, "\n");
984 return true;
985}
986
987// --------------------------------------------------------------------------
988//
989//!
990//
991bool Readline::Process(const string &str)
992{
993 if (str.substr(0, 3)==".w ")
994 {
995 usleep(stoi(str.substr(3))*1000);
996 return true;
997 }
998
999 if (str.substr(0, 3)==".x ")
1000 {
1001 Execute(str.substr(3));
1002 return true;
1003 }
1004
1005 if (str.substr(0, 2)==".!")
1006 {
1007 ExecuteShellCommand(str.substr(2));
1008 return true;
1009 }
1010
1011 // ----------- Readline static -------------
1012
1013 if (str=="clear")
1014 return ClearHistory();
1015
1016 if (str=="lh" || str=="history")
1017 return DumpHistory();
1018
1019 if (str=="v" || str=="variables")
1020 return DumpVariables();
1021
1022 if (str=="f" || str=="functions")
1023 return DumpFunctions();
1024
1025 if (str=="m" || str=="funmap")
1026 return DumpFunmap();
1027
1028 // ---------- Readline virtual -------------
1029
1030 if (str=="h" || str=="help")
1031 return PrintGeneralHelp();
1032
1033 if (str=="c" || str=="commands")
1034 return PrintCommands();
1035
1036 if (str=="k" || str=="keylist")
1037 return PrintKeyBindings();
1038
1039 return false;
1040}
1041
1042// --------------------------------------------------------------------------
1043//
1044//! This function is a wrapper around the call to readline. It encapsultes
1045//! the return buffer into a std::string and deletes the memory allocated
1046//! by readline. Furthermore, it removes leading and trailing whitespaces
1047//! before return the result. The result is returned in the given
1048//! argument containing the prompt. Before the function returns Shutdown()
1049//! is called (as opposed to Startup when readline starts)
1050//!
1051//! @param str
1052//! The prompt which is to be shown by the readline libarary. it is
1053//! directly given to the call to readline. The result of the
1054//! readline call is returned in this string.
1055//!
1056//! @returns
1057//! true if the call succeeded as usual, false if EOF was detected
1058//! by the readline call.
1059//
1060bool Readline::PromptEOF(string &str)
1061{
1062 char *buf = readline(str.c_str());
1063 Shutdown(buf);
1064
1065 // Happens when EOF is encountered
1066 if (!buf)
1067 return false;
1068
1069 str = Tools::Trim(buf);
1070
1071 free(buf);
1072
1073 return true;
1074}
1075
1076// --------------------------------------------------------------------------
1077//
1078//! This function is a wrapper around the call to readline. It encapsultes
1079//! the return buffer into a std::string and deletes the memory allocated
1080//! by readline. Furthermore, it removes leading and trailing whitespaces
1081//! before return the result. Before the function returns Shutdown() is
1082//! called (as opposed to Startup when readline starts)
1083//!
1084//! @param prompt
1085//! The prompt which is to be shown by the readline libarary. it is
1086//! directly given to the call to readline.
1087//!
1088//! @returns
1089//! The result of the readline call
1090//
1091string Readline::Prompt(const string &prompt)
1092{
1093 char *buf = readline(prompt.c_str());
1094
1095 Shutdown(buf ? buf : "");
1096
1097 const string str = !buf || (rl_done && rl_pending_input==4)
1098 ? ".q" : Tools::Trim(buf);
1099
1100 free(buf);
1101
1102 return str;
1103}
1104
1105// --------------------------------------------------------------------------
1106//
1107//! Process a single line. All lines are added to the history, but only
1108//! accepted lines are written to the command log. Inthis case fLine is
1109//! increased by one.
1110//
1111void Readline::ProcessLine(const string &str)
1112{
1113 const bool rc = Process(str);
1114
1115 AddToHistory(str);
1116
1117 if (rc)
1118 return;
1119
1120 fLine++;
1121
1122 fCommandLog << str << endl;
1123}
1124
1125// --------------------------------------------------------------------------
1126//
1127//! This implements a loop over readline calls. A prompt to issue can be
1128//! given. If it is NULL, the prompt is retrieved from GetUpdatePrompt().
1129//! It is updated regularly by means of calls to GetUpdatePrompt() from
1130//! EventHook(). If Prompt() returns with "quit" or ".q" the loop is
1131//! exited. If ".qqq" is entered exit(-1) is called. In case of ".qqqqqq"
1132//! abort(). Both ways to exit the program are not recommended. Empty
1133//! inputs are ignored. After that Process() with the returned string
1134//! is called. If Process returns true the input is not counted and not
1135//! added to the history, otherwise the line counter is increased
1136//! and the input is added to the history.
1137//!
1138//! @param prompt
1139//! The prompt to be issued or NULL if GetUPdatePrompt should be used
1140//! instead.
1141//!
1142void Readline::Run(const char *prompt)
1143{
1144 fLine = 0;
1145 while (1)
1146 {
1147 // Before we start we have to make sure that the
1148 // screen looks like and is ordered like expected.
1149 const string str = Prompt(prompt?prompt:GetUpdatePrompt());
1150 if (str.empty())
1151 continue;
1152
1153 if (str=="quit" || str==".q")
1154 break;
1155
1156 if (str==".qqq")
1157 exit(-1);
1158
1159 if (str==".qqqqqq")
1160 abort();
1161
1162 ProcessLine(str);
1163 }
1164}
1165
1166// --------------------------------------------------------------------------
1167//
1168//! Executes commands read from an ascii file as they were typed in
1169//! the console. Empty lines and lines beginning with # are ignored.
1170//!
1171//! @param fname
1172//! Filename of file to read
1173//!
1174//! @returns
1175//! -1 if the file couldn't be read and the number of command for which
1176//! Process() was callled otherwise
1177//!
1178int Readline::Execute(const string &fname)
1179{
1180 if (IsStopped())
1181 return 0;
1182
1183 int rc = 0;
1184
1185 const string name = Tools::Trim(fname);
1186
1187 ifstream fin(name.c_str());
1188 if (!fin)
1189 return -1;
1190
1191 fCommandLog << "# " << Time() << " - " << name << " (START)" << endl;
1192
1193 string buffer;
1194 while (getline(fin, buffer, '\n'))
1195 {
1196 buffer = Tools::Trim(buffer);
1197 if (buffer.empty())
1198 continue;
1199
1200 rc++;
1201
1202 if (buffer=="quit" || buffer==".q")
1203 {
1204 Stop();
1205 break;
1206 }
1207
1208 ProcessLine(buffer);
1209 }
1210
1211 fCommandLog << "# " << Time() << " - " << name << " (FINISHED)" << endl;
1212
1213 return rc;
1214}
1215
1216// --------------------------------------------------------------------------
1217//
1218//! Stops the readline execution. It fakes the end of an editing by
1219//! setting rl_done to 1. To distinguish this from a normal edit,
1220//! rl_pending_input is set to EOT.
1221//!
1222void Readline::Stop()
1223{
1224 rl_done = 1;
1225 rl_pending_input = 4; // EOT (end of transmission, ctrl-d)
1226}
1227
1228// --------------------------------------------------------------------------
1229//
1230//! @returns
1231//! the status of rl_done and rl_pending_input. If rl_done==1 and
1232//! rl_pending_input==4 true is returned, false otherwise.
1233//! This can be used to check if Stop() was called. If readline is
1234//! not in operation.
1235//!
1236bool Readline::IsStopped() const
1237{
1238 return rl_done==1 && rl_pending_input==4;
1239};
Note: See TracBrowser for help on using the repository browser.