pike.git / src / modules / _Stdio / buffer.cmod

version» Context lines:

pike.git/src/modules/_Stdio/buffer.cmod:66:    */   PIKECLASS Buffer   {   #if PRECOMPILE_API_VERSION > 5    PIKEVAR int b.num_malloc;    PIKEVAR int b.num_move;   #endif       CVAR Buffer b;    +  EXTRA +  { +  PIKE_MAP_VARIABLE("__output", OFFSETOF(Buffer_struct, b.output), +  tMix, PIKE_T_MIXED, ID_PRIVATE|ID_HIDDEN|ID_PROTECTED); +  } +     static void io_set_error_mode( Buffer *io, struct program *m )    {    if( m ) add_ref(m);    if( io->error_mode ) free_program( io->error_mode );    io->error_mode = m;    }       static size_t io_len( Buffer *io )    {    return io->len-io->offset;
pike.git/src/modules/_Stdio/buffer.cmod:402:    rew->rewind_to = io->len;    SET_ONERROR( (*x), io_do_unwrite_on_error, rew );    }       static void io_unset_unwrite_on_error( Buffer *UNUSED(io), ONERROR *x )    {    UNSET_ONERROR( (*x) );    free( x->arg );    }    -  static ptrdiff_t io_call_write( Buffer *io, struct object *o, ptrdiff_t nbytes ) +  static ptrdiff_t io_call_write( Buffer *io, struct svalue *fun, +  ptrdiff_t nbytes )    ATTRIBUTE((noclone,noinline));       static void io_set_events( Buffer *io, struct my_file *fd, int extra, int set )    ATTRIBUTE((noclone,noinline));       static void io_set_events( Buffer *UNUSED(io), struct my_file *fd, int extra, int set )    {    fd->box.revents &= ~((1<<set)|extra);    if(!SAFE_IS_ZERO(&fd->event_cbs[set]) && fd->box.backend)    set_fd_callback_events(&fd->box, fd->box.events|(1<<set), 0);    }    -  static ptrdiff_t io_call_write( Buffer *io, struct object *o, ptrdiff_t bytes ) +  static ptrdiff_t io_call_write( Buffer *io, struct svalue *fun, +  ptrdiff_t bytes )    {    if( bytes > 0 )    {    ptrdiff_t l = 0;    struct pike_string *s = io_read_string( io,bytes );       if( s )    {    io->output_triggered = 1;    push_string( s ); -  apply( o, "write", 1 ); +  apply_svalue( fun, 1 ); +  if (UNLIKELY(TYPEOF(Pike_sp[-1]) != PIKE_T_INT)) { +  Pike_error("Invalid return value from write callback.\n"); +  }    l = Pike_sp[-1].u.integer;    pop_stack(); -  if( l < 0 ) +  if( l < 0 )    {    io_rewind( io, bytes );    return -1;    }    if( bytes > l )    io_rewind( io, bytes-l );    }    return l;    }    return -1;    }       static void io_actually_trigger_output( Buffer *io )    ATTRIBUTE((noclone,noinline));       static void io_actually_trigger_output( Buffer *io )    { -  struct my_file *fd; -  if( (fd = get_storage( io->output, file_program )) ) -  { +  struct program *prog; +  struct reference *ref; +  struct inherit *inh; +  +  if (UNLIKELY(!(prog = io->output.u.object->prog))) { +  /* Destructed object. */ +  free_svalue(&io->output); +  SET_SVAL(io->output, PIKE_T_INT, NUMBER_NUMBER, integer, 0); +  return 0; +  } +  ref = PTR_FROM_INT(prog, SUBTYPEOF(io->output)); +  inh = INHERIT_FROM_PTR(prog, ref); +  if ((inh->prog == file_program) && +  (ref->identifier_offset == fd_write_identifier_offset)) { +  /* Stdio.Fd::write */ +  struct my_file *fd = +  get_inherit_storage( io->output.u.object, ref->inherit_offset );    io_set_events( io, fd, PIKE_BIT_FD_WRITE_OOB, PIKE_FD_WRITE );    io->output_triggered = 1;    }    else -  io_call_write( io, io->output, MINIMUM( io_len(io), 100 ) ); +  io_call_write( io, &io->output, MINIMUM( io_len(io), 100 ) );    }       static void io_trigger_output( Buffer *io )    { -  if( UNLIKELY(io->output) && UNLIKELY(!io->output_triggered) ) +  if( UNLIKELY(io->output.u.object) && UNLIKELY(!io->output_triggered) )    io_actually_trigger_output(io);    }       static int io_range_error( Buffer *io, ptrdiff_t howmuch )    ATTRIBUTE((noclone,noinline));       static int io_range_error( Buffer *io, ptrdiff_t howmuch )    {    int res;    struct svalue *osp = Pike_sp;
pike.git/src/modules/_Stdio/buffer.cmod:930:    nbytes -= Pike_sp[-1].u.string->len;    pop_stack();    }    }       if (!bread) RETURN -1;       RETURN bread;    }    -  /*! @decl int __fd_set_output( object f ) +  /*! @decl int __fd_set_output( object|function(string:int) write_callback )    *!    *! This tells the buffer to trigger the write callback for the    *! specified filedescriptor when data is added to the buffer.    *!    *! This is used internally by Stdio.File to handle nonblocking    *! buffered mode, and is not really intended to be used directly.    *! -  *! If f is 0 the state is cleared. +  *! If @[write_callback] is @expr{0@} (zero) the state is cleared.    */ -  PIKEFUN void __fd_set_output( int(0..0)|object f ) +  PIKEFUN void __fd_set_output( int(0..0)|object|function f )    {    Buffer *io = THIS; -  if( io->output ) free_object(io->output); -  io->output_triggered = 0; -  if( TYPEOF(*f) != PIKE_T_OBJECT ) -  io->output = 0; -  else -  { -  io->output = f->u.object; -  add_ref(io->output); +  if( TYPEOF(*f) == PIKE_T_OBJECT ) { +  struct program *p = f->u.object->prog; +  if (p) { +  struct inherit *inh = p->inherits + SUBTYPEOF(*f); +  int write_fun_num; +  p = inh->prog; +  if ((write_fun_num = find_identifier("write", p)) == -1) { +  Pike_error("Function \"write\" not available in object.\n");    } -  +  SET_SVAL_TYPE_SUBTYPE(*f, PIKE_T_FUNCTION, write_fun_num);    } -  +  } else if (TYPEOF(*f) != PIKE_T_FUNCTION) { +  push_int(0); +  f = Pike_sp-1; +  } +  assign_svalue(&io->output, f); +  io->output_triggered = 0; +  }    -  /*! @decl int(-1..) output_to( Stdio.Stream f, int(0..)|void nbytes ) +  /*! @decl int(-1..) output_to( Stdio.Stream|function(string:int) fun, @ +  *! int(0..)|void nbytes )    *!    *! Write data from the buffer to the indicated file.    *! -  +  *! @param fun +  *! Write function. Either one of: +  *! @mixed +  *! @type Stdio.Stream +  *! A file object in which the function @expr{write()@} will +  *! be called. +  *! @type function(string:int) +  *! A function which will be called with a @expr{string(8bit)@} +  *! to write and is expected to return an @expr{int@} indicating +  *! the number of bytes successfully written or @expr{-1@} on +  *! failure. +  *! @endmixed +  *!    *! @param nbytes -  *! If @[nbytes] is not specified the whole buffer will be written -  *! if possible. Otherwise at most @[nbytes] will be written. +  *! If @[nbytes] is not specified the whole buffer will be written +  *! if possible. Otherwise at most @[nbytes] will be written.    *!    *! @returns    *! Will return the number of bytes that have been written successfully.    *! -  *! If no bytes have been written successfully and @expr{f->write()@} failed +  *! If no bytes have been written successfully and @expr{fun()@} failed    *! with an error, @expr{-1@} will be returned.    */ -  PIKEFUN int(-1..) output_to( object f, int|void nbytes ) +  PIKEFUN int(-1..) output_to( object|function(string:int) f, int|void nbytes )    {    Buffer *io = THIS;    ptrdiff_t written = 0; -  struct my_file *fd; +     ptrdiff_t sz = io_len( io ); -  int write_fun_num; -  struct inherit *inh; +  int write_fun_num = -1;       if( !sz )    {    io_range_error(io, sz);    sz = io_len(io);    }    if( nbytes )    sz = MINIMUM(nbytes->u.integer, sz);    -  if ((write_fun_num = find_identifier("write", f->prog)) == -1) { -  Pike_error("Cannot call unknown function \"write\".\n"); +  if( TYPEOF(*f) == PIKE_T_OBJECT ) { +  struct program *p = f->u.object->prog; +  if (LIKELY(p)) { +  struct inherit *inh = p->inherits + SUBTYPEOF(*f); +  p = inh->prog; +  if ((write_fun_num = find_identifier("write", p)) == -1) { +  Pike_error("Function \"write\" not available in object.\n");    } -  +  SET_SVAL_TYPE_SUBTYPE(*f, PIKE_T_FUNCTION, write_fun_num); +  } else { +  SIMPLE_BAD_ARG_ERROR("output_to", 1, "object|function"); +  } +  } else if (UNLIKELY(TYPEOF(*f) != PIKE_T_FUNCTION)) { +  SIMPLE_BAD_ARG_ERROR("output_to", 1, "object|function"); +  } else { +  write_fun_num = SUBTYPEOF(*f); +  }    -  inh = INHERIT_FROM_INT(f->prog, write_fun_num); +  if (write_fun_num != FUNCTION_BUILTIN) { +  struct program *prog = f->u.object->prog; +  struct reference *ref = PTR_FROM_INT(prog, write_fun_num); +  struct inherit *inh = INHERIT_FROM_PTR(prog, ref);    -  if( inh->prog == file_program ) -  { -  fd = get_inherit_storage( f, inh - f->prog->inherits ); -  +  if( (inh->prog == file_program) && +  (ref->identifier_offset == fd_write_identifier_offset) ) { +  struct my_file *fd = +  get_inherit_storage( f->u.object, ref->inherit_offset );    while( sz > written )    {    ptrdiff_t rd = MINIMUM(sz-written,4096);    unsigned char *ptr = io_read_pointer( io );    ptrdiff_t res;    res = fd_write( fd->box.fd, ptr, rd );    if( res == -1 && errno == EINTR )    continue;    if( res <= 0 ) {    fd->my_errno = errno;    if (!written) written = -1;    break;    }    io_consume( io, res );    written += res;    io_set_events( io, fd, PIKE_BIT_FD_WRITE_OOB, PIKE_FD_WRITE);    } -  +  RETURN written;    } -  else -  { -  /* some other object. Just call write */ +  } +  +  /* Some other object or function. Just call it. */    while( sz > written )    {    size_t rd = MINIMUM(sz-written,4096);    ptrdiff_t wr = io_call_write( io, f, rd );    if( wr <= 0 )    {    if (!written) written = -1;    break;    }    written += wr;    if( wr < 4096 )    break;    } -  } +     RETURN written;    }       /*! @decl int read_sint( int size )    *!    *! Read a network byte order two:s complement signed number of size n*8 bits, then    *! return it.    *!    *! Will return UNDEFINED if there is not enough buffer space    *! available unless error mode is set to throw errors.
pike.git/src/modules/_Stdio/buffer.cmod:2366:       INIT {    Buffer *this = THIS;    memset( this, 0, sizeof(Buffer));    this->this = Pike_fp->current_object;    }       EXIT {    Buffer *this = THIS;    io_unlink_external_storage( this ); -  if( this->output ) -  free_object(this->output); +     if( this->error_mode )    free_program( this->error_mode );    if( this->malloced )    free( this->buffer );    free(this->stash.ptr);    }         /*! @class RewindKey    *!
pike.git/src/modules/_Stdio/buffer.cmod:2446:    *! Destructs this @[RewindKey]    */    PIKEFUN void rewind() {    THIS->auto_mode = 1;    destruct_object(Pike_fp->current_object, DESTRUCT_GC);    }       PIKEFUN void create()    flags ID_PRIVATE;    { +  /* FIXME: The following zeroing isn't safe! */    THIS->obj = 0;    THIS->io = 0;    Pike_error("Not supported\n");    }    }   }            static struct object* io_create_rewind_key( Buffer *io, int auto_mode )