1#pike __REAL_VERSION__
2
3//! A string wrapper that pretends to be a @[Stdio.File] object
4//! in addition to some features of a @[Stdio.FILE] object.
5
6
7//! This constant can be used to distinguish a FakeFile object
8//! from a real @[Stdio.File] object.
9constant is_fake_file = 1;
10
11protected string data;
12protected int ptr;
13protected int(0..1) r;
14protected int(0..1) w;
15protected int mtime;
16
17protected function read_cb;
18protected function read_oob_cb;
19protected function write_cb;
20protected function write_oob_cb;
21protected function close_cb;
22
23//! @seealso
24//!   @[Stdio.File()->close()]
25int close(void|string direction) {
26  direction = lower_case(direction||"rw");
27  int cr = has_value(direction, "r");
28  int cw = has_value(direction, "w");
29
30  if(cr) {
31    r = 0;
32  }
33
34  if(cw) {
35    w = 0;
36  }
37
38  // FIXME: Close callback
39  return 1;
40}
41
42//! @decl void create(string data, void|string type, void|int pointer)
43//! @seealso
44//!   @[Stdio.File()->create()]
45void create(string _data, void|string type, int|void _ptr) {
46  if(!_data) error("No data string given to FakeFile.\n");
47  data = _data;
48  ptr = _ptr;
49  mtime = time();
50  if(type) {
51    type = lower_case(type);
52    if(has_value(type, "r"))
53      r = 1;
54    if(has_value(type, "w"))
55      w = 1;
56  }
57  else
58    r = w = 1;
59}
60
61protected string make_type_str() {
62  string type = "";
63  if(r) type += "r";
64  if(w) type += "w";
65  return type;
66}
67
68//! @seealso
69//!   @[Stdio.File()->dup()]
70this_program dup() {
71  return this_program(data, make_type_str(), ptr);
72}
73
74//! Always returns 0.
75//! @seealso
76//!   @[Stdio.File()->errno()]
77int errno() { return 0; }
78
79//! Returns size and the creation time of the string.
80Stdio.Stat stat() {
81  Stdio.Stat st = Stdio.Stat();
82  st->size = sizeof(data);
83  st->mtime=st->ctime=mtime;
84  st->atime=time();
85  return st;
86}
87
88//! @seealso
89//!   @[Stdio.File()->line_iterator()]
90String.SplitIterator line_iterator(int|void trim) {
91  if(trim)
92    return String.SplitIterator( data-"\r", '\n' );
93  return String.SplitIterator( data, '\n' );
94}
95
96protected mixed id;
97
98//! @seealso
99//!   @[Stdio.File()->query_id()]
100mixed query_id() { return id; }
101
102//! @seealso
103//!   @[Stdio.File()->set_id()]
104void set_id(mixed _id) { id = _id; }
105
106//! @seealso
107//!   @[Stdio.File()->read_function()]
108function(:string) read_function(int nbytes) {
109  return lambda() { return read(nbytes); };
110}
111
112//! @seealso
113//!   @[Stdio.File()->peek()]
114int(-1..1) peek(int|float|void timeout) {
115  if(!r) return -1;
116  if(ptr >= sizeof(data)) return 0;
117  return 1;
118}
119
120//! Always returns 0.
121//! @seealso
122//!   @[Stdio.File()->query_address()]
123string query_address(void|int(0..1) is_local) { return 0; }
124
125//! @seealso
126//!   @[Stdio.File()->read()]
127string read(void|int(0..) len, void|int(0..1) not_all) {
128  if(!r) return 0;
129  if (len < 0) error("Cannot read negative number of characters.\n");
130  int start=ptr;
131  ptr += len;
132  if(zero_type(len) || ptr>sizeof(data))
133    ptr = sizeof(data);
134
135  // FIXME: read callback
136  return data[start..ptr-1];
137}
138
139//! @seealso
140//!   @[Stdio.FILE()->gets()]
141string gets() {
142  if(!r) return 0;
143  string ret;
144  sscanf(data,"%*"+(string)ptr+"s%[^\n]",ret);
145  if(ret)
146  {
147    ptr+=sizeof(ret)+1;
148    if(ptr>sizeof(data))
149    {
150      ptr=sizeof(data);
151      if(!sizeof(ret))
152	ret = 0;
153    }
154  }
155
156  // FIXME: read callback
157  return ret;
158}
159
160//! @seealso
161//!   @[Stdio.FILE()->getchar()]
162int getchar() {
163  if(!r) return 0;
164  int c;
165  if(catch(c=data[ptr]))
166    c=-1;
167  else
168    ptr++;
169
170  // FIXME: read callback
171  return c;
172}
173
174//! @seealso
175//!   @[Stdio.FILE()->unread()]
176void unread(string s) {
177  if(!r) return;
178  if(data[ptr-sizeof(s)..ptr-1]==s)
179    ptr-=sizeof(s);
180  else
181  {
182    data=s+data[ptr..];
183    ptr=0;
184  }
185}
186
187//! @seealso
188//!   @[Stdio.File()->seek()]
189int seek(int pos, void|int mult, void|int add) {
190  if(mult)
191    pos = pos*mult+add;
192  if(pos<0)
193  {
194    pos = sizeof(data)+pos;
195    if( pos < 0 )
196	pos = 0;
197  }
198  ptr = pos;
199  if( ptr > strlen( data ) )
200      ptr = strlen(data);
201  return ptr;
202}
203
204//! Always returns 1.
205//! @seealso
206//!   @[Stdio.File()->sync()]
207int(1..1) sync() { return 1; }
208
209//! @seealso
210//!   @[Stdio.File()->tell()]
211int tell() { return ptr; }
212
213//! @seealso
214//!   @[Stdio.File()->truncate()]
215int(0..1) truncate(int length) {
216  data = data[..length-1];
217  return sizeof(data)==length;
218}
219
220//! @seealso
221//!   @[Stdio.File()->write()]
222int(-1..) write(string|array(string) str, mixed ... extra) {
223  if(!w) return -1;
224  if(arrayp(str)) str=str*"";
225  if(sizeof(extra)) str=sprintf(str, @extra);
226
227  if(ptr==sizeof(data)) {
228    data += str;
229    ptr = sizeof(data);
230  }
231  else if(sizeof(str)==1)
232    data[ptr++] = str[0];
233  else {
234    data = data[..ptr-1] + str + data[ptr+sizeof(str)..];
235    ptr += sizeof(str);
236  }
237
238  // FIXME: write callback
239  return sizeof(str);
240}
241
242//! @seealso
243//!   @[Stdio.File()->set_blocking]
244void set_blocking() {
245  close_cb = 0;
246  read_cb = 0;
247  read_oob_cb = 0;
248  write_cb = 0;
249  write_oob_cb = 0;
250}
251
252//! @seealso
253//!   @[Stdio.File()->set_blocking_keep_callbacks]
254void set_blocking_keep_callbacks() { }
255
256//! @seealso
257//!   @[Stdio.File()->set_blocking]
258void set_nonblocking(function rcb, function wcb, function ccb,
259		     function rocb, function wocb) {
260  read_cb = rcb;
261  write_cb = wcb;
262  close_cb = ccb;
263  read_oob_cb = rocb;
264  write_oob_cb = wocb;
265}
266
267//! @seealso
268//!   @[Stdio.File()->set_blocking_keep_callbacks]
269void set_nonblocking_keep_callbacks() { }
270
271
272//! @seealso
273//!   @[Stdio.File()->set_close_callback]
274void set_close_callback(function cb) { close_cb = cb; }
275
276//! @seealso
277//!   @[Stdio.File()->set_read_callback]
278void set_read_callback(function cb) { read_cb = cb; }
279
280//! @seealso
281//!   @[Stdio.File()->set_read_oob_callback]
282void set_read_oob_callback(function cb) { read_oob_cb = cb; }
283
284//! @seealso
285//!   @[Stdio.File()->set_write_callback]
286void set_write_callback(function cb) { write_cb = cb; }
287
288//! @seealso
289//!   @[Stdio.File()->set_write_oob_callback]
290void set_write_oob_callback(function cb) { write_oob_cb = cb; }
291
292
293//! @seealso
294//!   @[Stdio.File()->query_close_callback]
295function query_close_callback() { return close_cb; }
296
297//! @seealso
298//!   @[Stdio.File()->query_read_callback]
299function query_read_callback() { return read_cb; }
300
301//! @seealso
302//!   @[Stdio.File()->query_read_oob_callback]
303function query_read_oob_callback() { return read_oob_cb; }
304
305//! @seealso
306//!   @[Stdio.File()->query_write_callback]
307function query_write_callback() { return write_cb; }
308
309//! @seealso
310//!   @[Stdio.File()->query_write_oob_callback]
311function query_write_oob_callback() { return write_oob_cb; }
312
313string _sprintf(int t) {
314  return t=='O' && sprintf("%O(%d,%O)", this_program, sizeof(data),
315			   make_type_str());
316}
317
318
319// FakeFile specials.
320
321//! A FakeFile can be casted to a string.
322mixed cast(string to) {
323  switch(to) {
324  case "string": return data;
325  case "object": return this;
326  }
327  error("Can not cast object to %O.\n", to);
328}
329
330//! Sizeof on a FakeFile returns the size of its contents.
331int(0..) _sizeof() {
332  return sizeof(data);
333}
334
335//! @ignore
336
337#define NOPE(X) mixed X (mixed ... args) { error("This is a FakeFile. %s is not available.\n", #X); }
338NOPE(assign);
339NOPE(async_connect);
340NOPE(connect);
341NOPE(connect_unix);
342NOPE(open);
343NOPE(open_socket);
344NOPE(pipe);
345NOPE(tcgetattr);
346NOPE(tcsetattr);
347
348// Stdio.Fd
349NOPE(dup2);
350NOPE(lock); // We could implement this
351NOPE(mode); // We could implement this
352NOPE(proxy); // We could implement this
353NOPE(query_fd);
354NOPE(read_oob);
355NOPE(set_close_on_exec);
356NOPE(set_keepalive);
357NOPE(trylock); // We could implement this
358NOPE(write_oob);
359
360//! @endignore