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

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