• Main Page
  • Modules
  • Classes
  • Files
  • File List
  • File Members

wsd.cc

00001 #include "wvfdstream.h"
00002 #include "wvistreamlist.h"
00003 #include "wvstrutils.h"
00004 #include "wvunixsocket.h"
00005 #include <readline/readline.h>
00006 #include <readline/history.h>
00007 
00008 #ifndef MACOS // The version of READLINE shipped with MacOS is brain damaged.
00009 
00010 class WvReadLineStream : public WvStream
00011 {
00012     static WvReadLineStream *me;
00013     WvStream *base;
00014     WvString prompt;
00015     WvDynBuf line_buf;
00016     WvStringList commands;
00017 
00018     virtual size_t uread(void *_buf, size_t count)
00019     {
00020         size_t result = 0;
00021         char *buf = (char *)_buf;
00022         while (count > 0 && line_buf.used() > 0)
00023         {
00024             size_t chunk = line_buf.optgettable();
00025             if (chunk > count)
00026                 chunk = count;
00027             memcpy(buf, line_buf.get(chunk), chunk);
00028             count -= chunk;
00029             buf += chunk;
00030             result += chunk;
00031         }
00032         return result;
00033     }
00034 
00035     virtual size_t uwrite(const void *_buf, size_t count)
00036     {
00037         const char *buf = (const char *)_buf;
00038         for (size_t i=0; i<count; ++i)
00039         {
00040             if (buf[i] == '\n')
00041                 rl_crlf();
00042             else
00043                 rl_show_char(buf[i]);
00044         }
00045         return count;        
00046     }
00047 
00048     static void readline_callback(char *str)
00049     {
00050         if (str == NULL)
00051             return;
00052         size_t len = strlen(str);
00053         if (len == 0)
00054             return;
00055         me->line_buf.put(str, len);
00056         me->line_buf.putch('\n');
00057         add_history(str);
00058     }
00059 
00060     static int readline_getc(FILE *)
00061     {
00062         char ch;
00063         assert(me->base->read(&ch, 1) == 1);
00064         return ch;
00065     }
00066 
00067     static char *readline_command_completion_function(const char *text, int state)
00068     {
00069         static int skip = 0;
00070         if (state == 0)
00071             skip = 0;
00072         int my_skip = skip;
00073         size_t len = strlen(text);
00074         WvStringList::Iter i(me->commands);
00075         for (i.rewind(); i.next(); )
00076         {
00077             if (my_skip-- > 0)
00078                 continue;
00079             ++skip;
00080             if (i->len() >= len && strncmp(*i, text, len) == 0)
00081                 return strdup(*i);
00082         }
00083         return NULL;       
00084     }
00085 
00086     virtual void pre_select(SelectInfo &si)
00087     {
00088         if (si.wants.readable && line_buf.used() > 0)
00089             si.msec_timeout = 0;
00090         
00091         base->pre_select(si);
00092     }
00093 
00094     virtual bool post_select(SelectInfo &si)
00095     {
00096         bool now = false;
00097         if (si.wants.readable && line_buf.used() > 0)
00098             now = true;
00099 
00100         while (base->isreadable())
00101             rl_callback_read_char();
00102         return base->post_select(si) || now;
00103     }
00104 
00105 public:
00106 
00107     WvReadLineStream(WvStream *_base, WvStringParm _prompt)
00108     {
00109         base = _base;
00110         prompt = _prompt;
00111 
00112         assert(!me);
00113         me = this;
00114         set_wsname("readline on %s", base->wsname());
00115         rl_already_prompted = 1;
00116         rl_completion_entry_function = readline_command_completion_function;
00117         rl_callback_handler_install(prompt, readline_callback);
00118         rl_getc_function = readline_getc;
00119     }
00120 
00121     ~WvReadLineStream()
00122     {
00123         rl_getc_function = NULL;
00124         rl_callback_handler_remove();
00125         me = NULL;
00126     }
00127 
00128     virtual bool isok() const
00129     {
00130         return WvStream::isok() && base->isok();
00131     }
00132 
00133     void display_prompt()
00134     {
00135         base->print("%s", prompt);
00136         rl_already_prompted = 1;
00137     }
00138 
00139     void set_commands(const WvStringList &_commands)
00140     {
00141         commands.zap();
00142         WvStringList::Iter i(_commands);
00143         for (i.rewind(); i.next(); )
00144             commands.append(*i);
00145     }
00146 
00147     const char *wstype() const { return "WvReadLineStream"; }
00148 };
00149 
00150 
00151 WvReadLineStream *WvReadLineStream::me = NULL;
00152 
00153 
00154 void remote_cb(WvStream &remote, WvReadLineStream &local)
00155 {
00156     const char *line = remote.getline();
00157     if (line == NULL)
00158         return;
00159 
00160     WvStringList words;
00161     wvtcl_decode(words, line);
00162 
00163     WvString first = words.popstr();
00164     bool last_line = !!first && first != "-";
00165     if (last_line)
00166         local.print("%s ", first);
00167     local.print("%s\n", words.join(" "));
00168     if (last_line)
00169         local.display_prompt();
00170 
00171     if (words.popstr() == "Commands availible:")
00172         local.set_commands(words);
00173 }
00174 
00175 
00176 void local_cb(WvReadLineStream &local, WvStream &remote)
00177 {
00178     const char *line = local.getline();
00179     if (line == NULL)
00180         return;
00181 
00182     if (strcmp(line, "quit") == 0)
00183         remote.close();
00184 
00185     remote.print("%s\n", line);
00186 }
00187 
00188 
00189 int main(int argc, char **argv)
00190 {
00191     WvReadLineStream readlinestream(wvcon, "> ");
00192 
00193     const char *sockname = "/tmp/weaver.wsd";
00194     if (argc >= 2)
00195         sockname = argv[1];
00196 
00197     WvUnixConn *s = new WvUnixConn(sockname);
00198     if (!s->isok())
00199     {
00200         wverr->print("Failed to connect to %s: %s\n",
00201                 sockname, s->errstr());
00202         return 1;
00203     }
00204     s->set_wsname("%s", sockname);
00205     s->print("help\n");
00206 
00207     s->setcallback(wv::bind(remote_cb, wv::ref(*s), wv::ref(readlinestream)));
00208     WvIStreamList::globallist.append(s, true, "wvstreams debugger client");
00209 
00210     readlinestream.setcallback(wv::bind(local_cb, wv::ref(readlinestream),
00211                                         wv::ref(*s)));
00212     WvIStreamList::globallist.append(&readlinestream, false, 
00213                                      "wvstreams debugger readline");
00214 
00215     while (s->isok() && readlinestream.isok())
00216         WvIStreamList::globallist.runonce();
00217 
00218     return 0;
00219 }
00220 
00221 #endif // Apple brain damaged Readline.

Generated on Thu Aug 12 2010 11:33:09 for WvStreams by  doxygen 1.7.1