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

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