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

Generated on Fri Oct 5 18:20:27 2007 for WvStreams by  doxygen 1.5.3