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 ...
const T * get(size_t count)
Reads exactly the specified number of elements and returns a pointer to a storage location owned by t...
void put(const T *data, size_t count)
Writes the specified number of elements from the specified storage location into the buffer at its ta...
size_t used() const
Returns the number of elements in the buffer currently available for reading.
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
virtual bool isok() const
return true if the stream is actually usable right now
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 ...
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();.
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...
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.
WvString join(const char *joinchars=" ") const
concatenates all elements of the list seperating on joinchars
WvString popstr()
get the first string in the list, or an empty string if the list is empty.
WvString is an implementation of a simple and efficient printable-string class.
WvStream-based Unix domain socket connection class.
void wvtcl_decode(WvList< WvString > &l, WvStringParm _s, const WvStringMask &splitchars=WVTCL_SPLITCHARS, bool do_unescape=true)
split a tcl-style list.
the data structure used by pre_select()/post_select() and internally by select().