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

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