WvStreams
wsd.cc
1#include "wvfdstream.h"
2#include "wvistreamlist.h"
3#include "wvstrutils.h"
4#include "wvunixsocket.h"
5#include <readline/readline.h>
6#include <readline/history.h>
7
8#ifndef MACOS // The version of READLINE shipped with MacOS is brain damaged.
9
11{
12 static WvReadLineStream *me;
13 WvStream *base;
14 WvString prompt;
15 WvDynBuf line_buf;
16 WvStringList commands;
17
18 virtual size_t uread(void *_buf, size_t count)
19 {
20 size_t result = 0;
21 char *buf = (char *)_buf;
22 while (count > 0 && line_buf.used() > 0)
23 {
24 size_t chunk = line_buf.optgettable();
25 if (chunk > count)
26 chunk = count;
27 memcpy(buf, line_buf.get(chunk), chunk);
28 count -= chunk;
29 buf += chunk;
30 result += chunk;
31 }
32 return result;
33 }
34
35 virtual size_t uwrite(const void *_buf, size_t count)
36 {
37 const char *buf = (const char *)_buf;
38 for (size_t i=0; i<count; ++i)
39 {
40 if (buf[i] == '\n')
41 rl_crlf();
42 else
43 rl_show_char(buf[i]);
44 }
45 return count;
46 }
47
48 static void readline_callback(char *str)
49 {
50 if (str == NULL)
51 return;
52 size_t len = strlen(str);
53 if (len == 0)
54 return;
55 me->line_buf.put(str, len);
56 me->line_buf.putch('\n');
57 add_history(str);
58 }
59
60 static int readline_getc(FILE *)
61 {
62 char ch;
63 assert(me->base->read(&ch, 1) == 1);
64 return ch;
65 }
66
67 static char *readline_command_completion_function(const char *text, int state)
68 {
69 static int skip = 0;
70 if (state == 0)
71 skip = 0;
72 int my_skip = skip;
73 size_t len = strlen(text);
74 WvStringList::Iter i(me->commands);
75 for (i.rewind(); i.next(); )
76 {
77 if (my_skip-- > 0)
78 continue;
79 ++skip;
80 if (i->len() >= len && strncmp(*i, text, len) == 0)
81 return strdup(*i);
82 }
83 return NULL;
84 }
85
86 virtual void pre_select(SelectInfo &si)
87 {
88 if (si.wants.readable && line_buf.used() > 0)
89 si.msec_timeout = 0;
90
91 base->pre_select(si);
92 }
93
94 virtual bool post_select(SelectInfo &si)
95 {
96 bool now = false;
97 if (si.wants.readable && line_buf.used() > 0)
98 now = true;
99
100 while (base->isreadable())
101 rl_callback_read_char();
102 return base->post_select(si) || now;
103 }
104
105public:
106
107 WvReadLineStream(WvStream *_base, WvStringParm _prompt)
108 {
109 base = _base;
110 prompt = _prompt;
111
112 assert(!me);
113 me = this;
114 set_wsname("readline on %s", base->wsname());
115 rl_already_prompted = 1;
116 rl_completion_entry_function = readline_command_completion_function;
117 rl_callback_handler_install(prompt, readline_callback);
118 rl_getc_function = readline_getc;
119 }
120
122 {
123 rl_getc_function = NULL;
124 rl_callback_handler_remove();
125 me = NULL;
126 }
127
128 virtual bool isok() const
129 {
130 return WvStream::isok() && base->isok();
131 }
132
133 void display_prompt()
134 {
135 base->print("%s", prompt);
136 rl_already_prompted = 1;
137 }
138
139 void set_commands(const WvStringList &_commands)
140 {
141 commands.zap();
142 WvStringList::Iter i(_commands);
143 for (i.rewind(); i.next(); )
144 commands.append(*i);
145 }
146
147 const char *wstype() const { return "WvReadLineStream"; }
148};
149
150
151WvReadLineStream *WvReadLineStream::me = NULL;
152
153
154void remote_cb(WvStream &remote, WvReadLineStream &local)
155{
156 const char *line = remote.getline();
157 if (line == NULL)
158 return;
159
160 WvStringList words;
161 wvtcl_decode(words, line);
162
163 WvString first = words.popstr();
164 bool last_line = !!first && first != "-";
165 if (last_line)
166 local.print("%s ", first);
167 local.print("%s\n", words.join(" "));
168 if (last_line)
169 local.display_prompt();
170
171 if (words.popstr() == "Commands availible:")
172 local.set_commands(words);
173}
174
175
176void local_cb(WvReadLineStream &local, WvStream &remote)
177{
178 const char *line = local.getline();
179 if (line == NULL)
180 return;
181
182 if (strcmp(line, "quit") == 0)
183 remote.close();
184
185 remote.print("%s\n", line);
186}
187
188
189int main(int argc, char **argv)
190{
191 WvReadLineStream readlinestream(wvcon, "> ");
192
193 const char *sockname = "/tmp/weaver.wsd";
194 if (argc >= 2)
195 sockname = argv[1];
196
197 WvUnixConn *s = new WvUnixConn(sockname);
198 if (!s->isok())
199 {
200 wverr->print("Failed to connect to %s: %s\n",
201 sockname, s->errstr());
202 return 1;
203 }
204 s->set_wsname("%s", sockname);
205 s->print("help\n");
206
207 s->setcallback(wv::bind(remote_cb, wv::ref(*s), wv::ref(readlinestream)));
208 WvIStreamList::globallist.append(s, true, "wvstreams debugger client");
209
210 readlinestream.setcallback(wv::bind(local_cb, wv::ref(readlinestream),
211 wv::ref(*s)));
212 WvIStreamList::globallist.append(&readlinestream, false,
213 "wvstreams debugger readline");
214
215 while (s->isok() && readlinestream.isok())
216 WvIStreamList::globallist.runonce();
217
218 return 0;
219}
220
221#endif // Apple brain damaged Readline.
size_t optgettable() const
Returns the optimal maximum number of elements in the buffer currently available for reading without ...
Definition: wvbufbase.h:154
const T * get(size_t count)
Reads exactly the specified number of elements and returns a pointer to a storage location owned by t...
Definition: wvbufbase.h:114
size_t used() const
Returns the number of elements in the buffer currently available for reading.
Definition: wvbufbase.h:92
void putch(int ch)
Puts a single character into the buffer as an int.
Definition: wvbuf.h:76
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
Definition: wvstring.h:94
virtual bool isok() const
return true if the stream is actually usable right now
Definition: wvfdstream.cc:134
virtual bool isok() const
return true if the stream is actually usable right now
Definition: wsd.cc:128
Unified support for streams, that is, sequences of bytes that may or may not be ready for read/write ...
Definition: wvstream.h:25
virtual bool post_select(SelectInfo &si)
post_select() is called after ::select(), and returns true if this object is now ready.
Definition: wvstream.cc:875
virtual bool isreadable()
Returns true if the stream is readable.
Definition: wvstream.cc:590
virtual bool isok() const
return true if the stream is actually usable right now
Definition: wvstream.cc:445
void setcallback(IWvStreamCallback _callfunc)
define the callback function for this stream, called whenever the callback() member is run,...
Definition: wvstream.cc:1129
virtual void pre_select(SelectInfo &si)
pre_select() sets up for eventually calling ::select().
Definition: wvstream.cc:844
void runonce(time_t msec_timeout=-1)
Exactly the same as: if (select(timeout)) callback();.
Definition: wvstream.h:391
char * getline(time_t wait_msec=0, char separator='\n', int readahead=1024)
Read up to one line of data from the stream and return a pointer to the internal buffer containing th...
Definition: wvstream.h:175
virtual size_t read(void *buf, size_t count)
read a data block on the stream.
Definition: wvstream.cc:490
virtual void close()
Close the stream if it is open; isok() becomes false from now on.
Definition: wvstream.cc:341
This is a WvList of WvStrings, and is a really handy way to parse strings.
Definition: wvstringlist.h:28
WvString join(const char *joinchars=" ") const
concatenates all elements of the list seperating on joinchars
Definition: wvstringlist.cc:14
WvString popstr()
get the first string in the list, or an empty string if the list is empty.
Definition: wvstringlist.cc:55
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:330
WvStream-based Unix domain socket connection class.
Definition: wvunixsocket.h:34
the data structure used by pre_select()/post_select() and internally by select().
Definition: iwvstream.h:50
Various little string functions.
void wvtcl_decode(WvList< WvString > &l, WvStringParm _s, const WvStringMask &splitchars=WVTCL_SPLITCHARS, bool do_unescape=true)
split a tcl-style list.
Definition: wvtclstring.cc:386