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

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