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

Last change on this file since 13492 was 12961, checked in by tbretz, 13 years ago
Implementd jumps and labels
File size: 36.4 KB
Line 
1// **************************************************************************
2/** @class Readline
3
4@brief C++ wrapper for GNU's readline library
5
6This class is meant as a C++ wrapper around GNU's readline library.
7Note that because readline uses a global namespace only one instance
8of this class can exist at a time. Instantiating a second object after
9a first one was deleted might show unexpected results.
10
11When the object is instantiated readline's history is read from a file.
12At destruction the history in memory is copied back to that file.
13The history file will be truncated to fMaxLines.
14
15By overloading the Readline class the function used for auto-completion
16can be overwritten.
17
18Simple example:
19
20\code
21
22 Readline rl("MyProg"); // will read the history from "MyProg.his"
23 while (1)
24 {
25 string txt = rl.Prompt("prompt> ");
26 if (txt=="quit)
27 break;
28
29 // ... do something ...
30
31 rl.AddHistory(txt);
32 }
33
34 // On destruction the history will be written to the file
35
36\endcode
37
38Simpler example (you need to implement the Process() function)
39
40\code
41
42 Readline rl("MyProg"); // will read the history from "MyProg.his"
43 rl.Run("prompt> ");
44
45 // On destruction the history will be written to the file
46
47\endcode
48
49@section References
50
51 - <A HREF="http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html">GNU Readline</A>
52
53 */
54// **************************************************************************
55#include "Readline.h"
56
57#include <sstream>
58#include <fstream>
59#include <iostream>
60
61#include <readline/readline.h>
62#include <readline/history.h>
63
64#include <boost/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), fLabel(-1), 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, " .x file:N Execute a script of commands, start at label N\n");
955 fprintf(rl_outstream, " .j N Forward jump to label N\n");
956 fprintf(rl_outstream, " : N Defines a label\n");
957 fprintf(rl_outstream, " .q,quit Quit\n");
958 fprintf(rl_outstream, "\n");
959 fprintf(rl_outstream, " The command history is automatically loaded and saves to\n");
960 fprintf(rl_outstream, " and from %s.\n", GetName().c_str());
961 fprintf(rl_outstream, "\n");
962 return true;
963}
964
965// --------------------------------------------------------------------------
966//
967//! Print a help text about key bindings. This is intended for being
968//! overwritten by deriving classes.
969//!
970//!
971//! rl_outstream can be redirected using SetStreamOut()
972//!
973//! @returns
974//! always true
975//
976//
977bool Readline::PrintKeyBindings()
978{
979 fprintf(rl_outstream, "\n");
980 fprintf(rl_outstream, " Key bindings:\n");
981 fprintf(rl_outstream, " Page-up Search backward in history\n");
982 fprintf(rl_outstream, " Page-dn Search forward in history\n");
983 fprintf(rl_outstream, " Ctrl-left One word backward\n");
984 fprintf(rl_outstream, " Ctrl-right One word forward\n");
985 fprintf(rl_outstream, " Ctrl-d Quit\n");
986 fprintf(rl_outstream, " Ctrl-y Delete line\n");
987 fprintf(rl_outstream, " Alt-end/Ctrl-k Delete until the end of the line\n");
988 fprintf(rl_outstream, " F1 Toggle visibility of upper panel\n");
989 fprintf(rl_outstream, "\n");
990 fprintf(rl_outstream, " Default key-bindings are identical with your bash.\n");
991 fprintf(rl_outstream, "\n");
992 return true;
993}
994
995// --------------------------------------------------------------------------
996//
997//!
998//
999bool Readline::PreProcess(const string &str)
1000{
1001 // ----------- Labels -------------
1002
1003 if (str[0]==':')
1004 {
1005 if (fLabel!=atoi(str.substr(1).c_str()))
1006 return true;
1007
1008 fLabel=-1;
1009 return false;
1010 }
1011
1012 if (fLabel>=0)
1013 {
1014 fCommandLog << "# SKIP[" << fLabel << "]: " << str << endl;
1015 return true;
1016 }
1017
1018 if (str.substr(0, 3)==".j ")
1019 {
1020 fLabel = atoi(str.substr(3).c_str());
1021 return false;
1022 }
1023
1024 return Process(str);
1025
1026}
1027
1028// --------------------------------------------------------------------------
1029//
1030//!
1031//
1032bool Readline::Process(const string &str)
1033{
1034 // ----------- Common commands -------------
1035
1036 if (str.substr(0, 3)==".w ")
1037 {
1038 usleep(stoi(str.substr(3))*1000);
1039 return true;
1040 }
1041
1042 if (str.substr(0, 3)==".x ")
1043 {
1044 Execute(str.substr(3));
1045 return true;
1046 }
1047
1048 if (str.substr(0, 2)==".!")
1049 {
1050 ExecuteShellCommand(str.substr(2));
1051 return true;
1052 }
1053
1054 // ----------- Readline static -------------
1055
1056 if (str=="clear")
1057 return ClearHistory();
1058
1059 if (str=="lh" || str=="history")
1060 return DumpHistory();
1061
1062 if (str=="v" || str=="variables")
1063 return DumpVariables();
1064
1065 if (str=="f" || str=="functions")
1066 return DumpFunctions();
1067
1068 if (str=="m" || str=="funmap")
1069 return DumpFunmap();
1070
1071 // ---------- Readline virtual -------------
1072
1073 if (str=="h" || str=="help")
1074 return PrintGeneralHelp();
1075
1076 if (str=="c" || str=="commands")
1077 return PrintCommands();
1078
1079 if (str=="k" || str=="keylist")
1080 return PrintKeyBindings();
1081
1082 return false;
1083}
1084
1085// --------------------------------------------------------------------------
1086//
1087//! This function is a wrapper around the call to readline. It encapsultes
1088//! the return buffer into a std::string and deletes the memory allocated
1089//! by readline. Furthermore, it removes leading and trailing whitespaces
1090//! before return the result. The result is returned in the given
1091//! argument containing the prompt. Before the function returns Shutdown()
1092//! is called (as opposed to Startup when readline starts)
1093//!
1094//! @param str
1095//! The prompt which is to be shown by the readline libarary. it is
1096//! directly given to the call to readline. The result of the
1097//! readline call is returned in this string.
1098//!
1099//! @returns
1100//! true if the call succeeded as usual, false if EOF was detected
1101//! by the readline call.
1102//
1103bool Readline::PromptEOF(string &str)
1104{
1105 char *buf = readline(str.c_str());
1106 Shutdown(buf);
1107
1108 // Happens when EOF is encountered
1109 if (!buf)
1110 return false;
1111
1112 str = Tools::Trim(buf);
1113
1114 free(buf);
1115
1116 return true;
1117}
1118
1119// --------------------------------------------------------------------------
1120//
1121//! This function is a wrapper around the call to readline. It encapsultes
1122//! the return buffer into a std::string and deletes the memory allocated
1123//! by readline. Furthermore, it removes leading and trailing whitespaces
1124//! before return the result. Before the function returns Shutdown() is
1125//! called (as opposed to Startup when readline starts)
1126//!
1127//! @param prompt
1128//! The prompt which is to be shown by the readline libarary. it is
1129//! directly given to the call to readline.
1130//!
1131//! @returns
1132//! The result of the readline call
1133//
1134string Readline::Prompt(const string &prompt)
1135{
1136 char *buf = readline(prompt.c_str());
1137
1138 Shutdown(buf ? buf : "");
1139
1140 const string str = !buf || (rl_done && rl_pending_input==4)
1141 ? ".q" : Tools::Trim(buf);
1142
1143 free(buf);
1144
1145 return str;
1146}
1147
1148// --------------------------------------------------------------------------
1149//
1150//! Process a single line. All lines are added to the history, but only
1151//! accepted lines are written to the command log. Inthis case fLine is
1152//! increased by one.
1153//
1154void Readline::ProcessLine(const string &str)
1155{
1156 const bool rc = PreProcess(str);
1157
1158 AddToHistory(str);
1159
1160 if (rc)
1161 return;
1162
1163 fLine++;
1164
1165 fCommandLog << str << endl;
1166}
1167
1168// --------------------------------------------------------------------------
1169//
1170//! This implements a loop over readline calls. A prompt to issue can be
1171//! given. If it is NULL, the prompt is retrieved from GetUpdatePrompt().
1172//! It is updated regularly by means of calls to GetUpdatePrompt() from
1173//! EventHook(). If Prompt() returns with "quit" or ".q" the loop is
1174//! exited. If ".qqq" is entered exit(-1) is called. In case of ".qqqqqq"
1175//! abort(). Both ways to exit the program are not recommended. Empty
1176//! inputs are ignored. After that Process() with the returned string
1177//! is called. If Process returns true the input is not counted and not
1178//! added to the history, otherwise the line counter is increased
1179//! and the input is added to the history.
1180//!
1181//! @param prompt
1182//! The prompt to be issued or NULL if GetUPdatePrompt should be used
1183//! instead.
1184//!
1185void Readline::Run(const char *prompt)
1186{
1187 fLine = 0;
1188 while (1)
1189 {
1190 // Before we start we have to make sure that the
1191 // screen looks like and is ordered like expected.
1192 const string str = Prompt(prompt?prompt:GetUpdatePrompt());
1193 if (str.empty())
1194 continue;
1195
1196 if (str=="quit" || str==".q")
1197 break;
1198
1199 if (str==".qqq")
1200 exit(-1);
1201
1202 if (str==".qqqqqq")
1203 abort();
1204
1205 ProcessLine(str);
1206 }
1207}
1208
1209// --------------------------------------------------------------------------
1210//
1211//! Executes commands read from an ascii file as they were typed in
1212//! the console. Empty lines and lines beginning with # are ignored.
1213//!
1214//! @param fname
1215//! Filename of file to read
1216//!
1217//! @returns
1218//! -1 if the file couldn't be read and the number of command for which
1219//! Process() was callled otherwise
1220//!
1221int Readline::Execute(const string &fname)
1222{
1223 if (IsStopped())
1224 return 0;
1225
1226 fLabel = -1;
1227
1228 string name = Tools::Trim(fname);
1229
1230 const size_t p = name.find_last_of(':');
1231 if (p!=string::npos)
1232 {
1233 fLabel = atoi(name.substr(p+1).c_str());
1234 name = name.substr(0, p);
1235 }
1236
1237 ifstream fin(name.c_str());
1238 if (!fin)
1239 return -1;
1240
1241 fCommandLog << "# " << Time() << " - " << name << " (START";
1242 if (fLabel>=0)
1243 fCommandLog << ':' << fLabel;
1244 fCommandLog << ")" << endl;
1245
1246 int rc = 0;
1247
1248 string buffer;
1249 while (getline(fin, buffer, '\n'))
1250 {
1251 buffer = Tools::Trim(buffer);
1252 if (buffer.empty())
1253 continue;
1254
1255 rc++;
1256
1257 if (buffer=="quit" || buffer==".q")
1258 {
1259 Stop();
1260 break;
1261 }
1262
1263 ProcessLine(buffer);
1264 }
1265
1266 fLabel = -1;
1267
1268 fCommandLog << "# " << Time() << " - " << name << " (FINISHED)" << endl;
1269
1270 return rc;
1271}
1272
1273// --------------------------------------------------------------------------
1274//
1275//! Stops the readline execution. It fakes the end of an editing by
1276//! setting rl_done to 1. To distinguish this from a normal edit,
1277//! rl_pending_input is set to EOT.
1278//!
1279void Readline::Stop()
1280{
1281 rl_done = 1;
1282 rl_pending_input = 4; // EOT (end of transmission, ctrl-d)
1283}
1284
1285// --------------------------------------------------------------------------
1286//
1287//! @returns
1288//! the status of rl_done and rl_pending_input. If rl_done==1 and
1289//! rl_pending_input==4 true is returned, false otherwise.
1290//! This can be used to check if Stop() was called. If readline is
1291//! not in operation.
1292//!
1293bool Readline::IsStopped() const
1294{
1295 return rl_done==1 && rl_pending_input==4;
1296};
Note: See TracBrowser for help on using the repository browser.