e576bb2002-10-11Martin Nilsson /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */
1b10db2002-10-08Martin Nilsson 
22363a2002-05-30Per Hedbor #include "global.h" #include "bignum.h" #include "object.h" #include "interpret.h" #include "fdlib.h" #include "fd_control.h" #include <sys/stat.h> #include "shuffler.h"
67c6c42002-11-07Martin Nilsson /* Source: Pike-Stream
22363a2002-05-30Per Hedbor  * Argument: Stdio.File lookalike with read * callback support (set_read_callback) */
1558d72019-06-22Stephen R. van den Berg static struct program *source_program; #ifdef THIS #undef THIS #endif #define THIS ((struct pf_source *)(Pike_fp->current_storage))
22363a2002-05-30Per Hedbor  struct pf_source { struct source s;
1558d72019-06-22Stephen R. van den Berg  struct object *self;
22363a2002-05-30Per Hedbor  struct object *obj; struct pike_string *str;
a42f7c2019-06-21Stephen R. van den Berg  char *data; size_t available; int eof;
22363a2002-05-30Per Hedbor  void (*when_data_cb)( void *a );
6504eb2019-06-25Stephen R. van den Berg  struct object *when_data_cb_arg;
22363a2002-05-30Per Hedbor  size_t len, skip; };
feb6822009-08-13Henrik Grubbström (Grubba) static void setup_callbacks( struct source *src )
22363a2002-05-30Per Hedbor {
feb6822009-08-13Henrik Grubbström (Grubba)  struct pf_source *s = (struct pf_source *)src;
1558d72019-06-22Stephen R. van den Berg  ref_push_object(s->self); apply(s->obj, "set_read_callback", 1);
a42f7c2019-06-21Stephen R. van den Berg  pop_stack();
1558d72019-06-22Stephen R. van den Berg  ref_push_object(s->self); apply(s->obj, "set_close_callback", 1);
a42f7c2019-06-21Stephen R. van den Berg  pop_stack();
22363a2002-05-30Per Hedbor }
feb6822009-08-13Henrik Grubbström (Grubba) static void remove_callbacks( struct source *src )
22363a2002-05-30Per Hedbor {
feb6822009-08-13Henrik Grubbström (Grubba)  struct pf_source *s = (struct pf_source *)src;
1558d72019-06-22Stephen R. van den Berg  if (s->obj && s->obj->prog) {
a42f7c2019-06-21Stephen R. van den Berg  push_int(0);
1558d72019-06-22Stephen R. van den Berg  apply(s->obj, "set_read_callback", 1);
a42f7c2019-06-21Stephen R. van den Berg  pop_stack(); push_int(0);
1558d72019-06-22Stephen R. van den Berg  apply(s->obj, "set_close_callback", 1);
a42f7c2019-06-21Stephen R. van den Berg  pop_stack(); }
22363a2002-05-30Per Hedbor }
eb94452019-06-11Stephen R. van den Berg static void frees(struct pf_source*s) { if (s->str) { free_string(s->str); s->str = 0; } }
22363a2002-05-30Per Hedbor 
feb6822009-08-13Henrik Grubbström (Grubba) static struct data get_data( struct source *src, off_t len )
22363a2002-05-30Per Hedbor {
feb6822009-08-13Henrik Grubbström (Grubba)  struct pf_source *s = (struct pf_source *)src;
eb94452019-06-11Stephen R. van den Berg  struct data res;
b2986f2002-07-05Per Hedbor 
5403882019-08-08Henrik Grubbström (Grubba)  res.data = NULL;
a42f7c2019-06-21Stephen R. van den Berg  res.len = s->available; if (s->eof) s->s.eof = 1;
eb94452019-06-11Stephen R. van den Berg  if (s->available) {
a42f7c2019-06-21Stephen R. van den Berg  res.data = s->data;
eb94452019-06-11Stephen R. van den Berg  s->available = 0;
1558d72019-06-22Stephen R. van den Berg  } else if (!s->obj->prog) { /* Object imploded before we were done */ s->s.eof = 1; /* FIXME should we throw an error here? */
eb94452019-06-11Stephen R. van den Berg  } else {
22363a2002-05-30Per Hedbor  /* No data available, but there should be in the future (no EOF, nor * out of the range of data to send as specified by the arguments to * source_stream_make) */ res.len = -2;
ba96832019-06-14Stephen R. van den Berg  setup_callbacks(src);
eb94452019-06-11Stephen R. van den Berg  }
22363a2002-05-30Per Hedbor  return res; } static void f_got_data( INT32 args ) {
1558d72019-06-22Stephen R. van den Berg  struct pf_source *s = (struct pf_source*)Pike_fp->current_object->storage;
b8112e2019-06-24Stephen R. van den Berg  if (!s->obj) /* Already finished */ return; /* FIXME Should we throw an error here? */
22363a2002-05-30Per Hedbor  remove_callbacks( (struct source *)s );
a42f7c2019-06-21Stephen R. van den Berg  if (args < 2 || TYPEOF(Pike_sp[-1]) != PIKE_T_STRING) { s->eof = 1; /* signal EOF */ pop_n_elems(args); if (!s->available) goto cb;
8de3272019-06-21Stephen R. van den Berg  } else {
a42f7c2019-06-21Stephen R. van den Berg  size_t slen;
8de3272019-06-21Stephen R. van den Berg  frees(s); s->str = Pike_sp[-1].u.string;
a42f7c2019-06-21Stephen R. van den Berg  slen = s->str->len; if (!slen) Pike_error("Shuffler: Read callback passing a zero size string\n"); if (s->str->size_shift) Pike_error("Shuffler: Wide strings are not supported\n"); if (slen > s->skip) { s->available = slen -= s->skip; s->data = s->str->str + s->skip; s->skip = 0; Pike_sp--; args--; } else { s->skip -= slen; s->str = 0; } pop_n_elems(args);
6504eb2019-06-25Stephen R. van den Berg cb: if (s->when_data_cb) s->when_data_cb(s->when_data_cb_arg);
22363a2002-05-30Per Hedbor  }
8de3272019-06-21Stephen R. van den Berg  push_int(0);
22363a2002-05-30Per Hedbor }
6504eb2019-06-25Stephen R. van den Berg static void set_callback(struct source *src, void (*cb)( void *a ), struct object *a) {
feb6822009-08-13Henrik Grubbström (Grubba)  struct pf_source *s = (struct pf_source *)src;
22363a2002-05-30Per Hedbor  s->when_data_cb = cb;
6504eb2019-06-25Stephen R. van den Berg  if (!s->when_data_cb_arg) add_ref(s->when_data_cb_arg = a);
22363a2002-05-30Per Hedbor }
1558d72019-06-22Stephen R. van den Berg static void free_source( struct source *src ) { free_object(((struct pf_source *)src)->self); }
22363a2002-05-30Per Hedbor 
1558d72019-06-22Stephen R. van den Berg struct source *source_pikestream_make(struct svalue *sv, INT64 start, INT64 len) { struct pf_source *s;
13670c2015-05-25Martin Nilsson 
1558d72019-06-22Stephen R. van den Berg  if (TYPEOF(*sv) != PIKE_T_OBJECT || find_identifier("set_read_callback", sv->u.object->prog) < 0)
97611f2019-06-17Stephen R. van den Berg  return 0;
22363a2002-05-30Per Hedbor 
1558d72019-06-22Stephen R. van den Berg  { struct object *p; if (!(p = clone_object(source_program, 0))) return 0;
22363a2002-05-30Per Hedbor 
1558d72019-06-22Stephen R. van den Berg  s = (struct pf_source*)p->storage; s->self = p; }
22363a2002-05-30Per Hedbor 
1558d72019-06-22Stephen R. van den Berg  add_ref(s->obj = sv->u.object);
22363a2002-05-30Per Hedbor 
1558d72019-06-22Stephen R. van den Berg  s->len = len; s->skip = start; s->s.get_data = get_data; s->s.free_source = free_source; s->s.set_callback = set_callback; s->s.setup_callbacks = setup_callbacks; s->s.remove_callbacks = remove_callbacks; return (struct source *)s;
22363a2002-05-30Per Hedbor }
1558d72019-06-22Stephen R. van den Berg static void source_destruct(struct object *UNUSED(o)) { remove_callbacks((struct source*)THIS); free_object(THIS->obj); THIS->obj = 0;
6504eb2019-06-25Stephen R. van den Berg  if (THIS->when_data_cb_arg) free_object(THIS->when_data_cb_arg);
22363a2002-05-30Per Hedbor }
1558d72019-06-22Stephen R. van den Berg void source_pikestream_exit() { free_program(source_program); } void source_pikestream_init() {
22363a2002-05-30Per Hedbor  start_new_program();
1558d72019-06-22Stephen R. van den Berg  ADD_STORAGE(struct pf_source);
362e4e2016-01-29Martin Nilsson  ADD_FUNCTION("`()", f_got_data, tFunc(tInt tStr,tVoid),0);
1558d72019-06-22Stephen R. van den Berg  set_exit_callback(source_destruct); source_program = end_program();
22363a2002-05-30Per Hedbor }