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

version» Context lines:

pike.git/src/modules/_Stdio/buffer.cmod:83:    *!    *! @note    *! The "avoid copy" part means that a IOBuffer will never shrink    *! unless you call the @[trim] function.    *!    */   PIKECLASS IOBuffer   {    CVAR IOBuffer b;    + #if PRECOMPILE_API_VERSION > 5 +  PIKEVAR int b.num_malloc; +  PIKEVAR int b.num_move; + #endif +     static void io_set_error_mode( IOBuffer *io, struct program *m )    {    if( m ) m->refs++;    if( io->error_mode ) free_program( io->error_mode );    io->error_mode = m;    }       static size_t io_len( IOBuffer *io )    {    return io->len-io->offset;
pike.git/src/modules/_Stdio/buffer.cmod:135:    if( pos > io_len( io ) )    return -1;    switch( io->buffer[io->offset+pos] )    {    SPACECASE8    return 1;    }    return 0;    }    +  static void io_unlink_external_storage( IOBuffer *io ) +  ATTRIBUTE((noclone,noinline)); +  +  static void io_unlink_external_storage( IOBuffer *io ) +  { +  if( io->sub ) { +  io_unlock( get_storage(io->sub,IOBuffer_program ) ); +  free_object( io->sub ); +  } +  if( io->source ) free_object( io->source ); +  if( io->str ) free_string( io->str ); +  io->source = 0; +  io->sub = 0; +  io->str = 0; +  } +     static int io_unstash_malloc( IOBuffer *io )    {    if( LIKELY(!io->stash.ptr) )    return 0;       if( io->stash.len >= io_len( io ) )    {    if( io_len(io) )    {    /* do not count this one, since it comes from add and would    * have been a copy normally.    */    memcpy( io->stash.ptr, io_read_pointer( io ), io_len(io) );    }    io->buffer = io->stash.ptr; -  +  io->malloced = 1;    io->len = io_len(io);    io->offset = 0;    io->allocated = io->stash.len; -  if( io->sub ) { -  io_unlock( get_storage(io->sub,IOBuffer_program ) ); -  free_object( io->sub ); +  io_unlink_external_storage(io);    } -  if( io->source ) free_object( io->source ); -  if( io->str ) free_string( io->str ); -  io->source = 0; -  io->sub = 0; -  io->str = 0; -  io->malloced = 1; -  } +     else    free( io->stash.ptr );    io->stash.ptr = 0;    io->stash.len = 0;    return io->malloced;    }       static void io_stash_malloc( IOBuffer *io )    {    if( io->malloced )
pike.git/src/modules/_Stdio/buffer.cmod:188:    io->buffer = 0;    io->offset = 0;    }    }       static void io_ensure_malloced( IOBuffer *io, int bytes )    {    if( UNLIKELY(!io->malloced) )    {    /* convert to malloced buffer from a shared one. */ -  unsigned char *old = io->buffer; +     if( !io_unstash_malloc(io) )    { -  +  unsigned char *old = io->buffer;    io->buffer = xalloc( io->len + bytes + 100 ); -  +  io->malloced = 1;    io->allocated = io->len + bytes + 100;    io->num_malloc++;    memcpy( io->buffer, old, io->len ); -  if( io->sub ) { -  io_unlock( get_storage(io->sub,IOBuffer_program ) ); -  free_object( io->sub ); +  io_unlink_external_storage(io);    } -  if( io->source ) free_object( io->source ); -  if( io->str ) free_string( io->str ); -  io->source = 0; -  io->sub = 0; -  io->str = 0; -  io->malloced = 1; +     }    } -  } +        static unsigned char *io_add_space( IOBuffer *io, int bytes, int force )    {    io_ensure_unlocked(io);    io_ensure_malloced(io, bytes);       /*    * It is actually not certain that checking this is a good idea.    *    * The reason being that if the current buffer size is very small
pike.git/src/modules/_Stdio/buffer.cmod:365:    rew->old_locked_move = io->locked_move;   #endif    io->locked_move++;    rew->io = io;    rew->rewind_to = io->offset;    SET_ONERROR( (*x), io_do_rewind_on_error, rew );    }       static void io_unset_rewind_on_error( IOBuffer *io, ONERROR *x )    { -  struct rewind_to *rew = x->arg; -  -  UNSET_ONERROR( (*x) ); -  io->locked_move--; +    #if defined(PIKE_DEBUG) -  +  struct rewind_to *rew = x->arg;    if( io->locked_move != rew->old_locked_move )    Pike_fatal( "Invalid io_rewind_on_error nesting\n"); - #endif -  +     free( rew ); -  + #endif +  UNSET_ONERROR( (*x) ); +  io->locked_move--;    }    -  -  +     static void io_do_unwrite_on_error( struct rewind_to *e )    {    e->io->len = e->rewind_to;    free( e );    }       static void io_unwrite_on_error( IOBuffer *io, ONERROR *x )    {    struct rewind_to *rew = xalloc( sizeof( struct rewind_to ) );    rew->io = io;    rew->rewind_to = io->len;    SET_ONERROR( (*x), io_do_unwrite_on_error, rew );    }       static void io_unset_unwrite_on_error( IOBuffer *UNUSED(io), ONERROR *x )    {    UNSET_ONERROR( (*x) );    free( x->arg );    }    -  static void io_trigger_output( IOBuffer *io ) +  static ssize_t io_call_write( IOBuffer *io, struct object *o, ssize_t nbytes ) +  ATTRIBUTE((noclone,noinline)); +  +  static void io_set_events( IOBuffer *io, struct my_file *fd, int extra, int set ) +  ATTRIBUTE((noclone,noinline)); +  +  static void io_set_events( IOBuffer *UNUSED(io), struct my_file *fd, int extra, int set )    { -  if( io->output && !io->output_triggered ) -  { -  struct my_file *fd; -  if( (fd = get_storage( io->output, file_program )) ) -  { -  /* actual fd? Just register the callback. */ -  fd->box.revents &= ~(PIKE_BIT_FD_WRITE|PIKE_BIT_FD_WRITE_OOB); -  if(!SAFE_IS_ZERO(&fd->event_cbs[PIKE_FD_WRITE]) -  && fd->box.backend) -  set_fd_callback_events(&fd->box, fd->box.events|PIKE_BIT_FD_WRITE, 0); -  io->output_triggered = 1; +  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);    } -  else +  +  static ssize_t io_call_write( IOBuffer *io, struct object *o, ssize_t bytes )    { -  size_t bytes = MINIMUM(io_len(io),100); -  INT_TYPE l; +  if( bytes > 0 ) +  { +  ssize_t l = 0;    struct pike_string *s = io_read_string( io,bytes ); -  +     if( s )    { -  /* Call write to triggger. */ +     io->output_triggered = 1;    push_string( s ); -  apply( io->output, "write", 1 ); +  apply( o, "write", 1 );    l = Pike_sp[-1].u.integer;    pop_stack();    if( l < 0 ) -  l = 0; +  { +  io_rewind( io, bytes ); +  return -1; +  }    if( bytes > (unsigned)l )    io_rewind( io, bytes-l );    } -  +  return l;    } -  +  return -1;    } -  +  +  static void io_trigger_output( IOBuffer *io ) +  { +  if( io->output && !io->output_triggered ) +  { +  struct my_file *fd; +  if( (fd = get_storage( io->output, file_program )) ) +  { +  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 ) ); +  } +  }       static int io_range_error( IOBuffer *io, ssize_t howmuch )    ATTRIBUTE((noclone,noinline));       static int io_range_error( IOBuffer *io, ssize_t howmuch )    {    int res;    struct svalue *osp = Pike_sp;       push_int64( howmuch );
pike.git/src/modules/_Stdio/buffer.cmod:717:    }       if( (src.s = system_memory( x )) )    return src.s->size;    }    Pike_error("Illegal argument (not a string or buffer object)\n");    }       /* NOTE: Can return negative integers. */    static INT_TYPE get_small_int( struct svalue *s ) +  ATTRIBUTE((noclone,noinline)); +  +  static INT_TYPE get_small_int( struct svalue *s )    { -  if( TYPEOF(*s) == PIKE_T_INT ) +  if( LIKELY(TYPEOF(*s) == PIKE_T_INT) )    return s->u.integer; -  +     if( is_bignum_object_in_svalue( s ) )    {    INT64 i64;    if( int64_from_bignum( &i64, s->u.object ) )    return i64;    Pike_error("Too big bignum, can not fit in indicated width\n");    }    Pike_error("Non integer argument\n");    }   
pike.git/src/modules/_Stdio/buffer.cmod:868:       if( res <= 0 )    break;       nbytes -= res;    io->len += res;    bread += res;    if( res != 4096 || once)    break;    } -  fd->box.revents &= ~(PIKE_BIT_FD_READ|PIKE_BIT_FD_READ_OOB); -  if(!SAFE_IS_ZERO(&fd->event_cbs[PIKE_FD_READ]) -  && fd->box.backend) -  set_fd_callback_events(&fd->box, fd->box.events|PIKE_BIT_FD_READ, 0); +  io_set_events( io, fd, PIKE_BIT_FD_READ_OOB, PIKE_FD_READ );    }    else    {    /* some other object. Just call read */    while( nbytes )    {    push_int( MINIMUM(4096,nbytes) );    safe_apply( f, "read", 1 );    if( TYPEOF(Pike_sp[-1]) != PIKE_T_STRING || Pike_sp[-1].u.string->len == 0 )    break;
pike.git/src/modules/_Stdio/buffer.cmod:903:    *!    *! 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.    */    -  PIKEFUN void __fd_set_output( object f ) +  PIKEFUN void __fd_set_output( int(0..0)|object f )    {    IOBuffer *io = THIS;    if( io->output ) free_object(io->output);    io->output_triggered = 0; -  io->output = f; +  if( TYPEOF(*f) != PIKE_T_OBJECT ) +  io->output = 0; +  else +  { +  io->output = f->u.object;    io->output->refs++;    } -  -  PIKEFUN void __fd_set_output( int(0..0) f ) -  { -  IOBuffer *io = THIS; -  if( io->output ) free_object(io->output); -  io->output = 0; -  io->output_triggered = 0; +     }       /*! @decl int(-1..) output_to( Stdio.Stream f, int(0..)|void nbytes )    *!    *! Write data from the buffer to the indicated file.    *!    *! @param nbytes    *! If @[nbytes] is not specified the whole buffer will be written    *! if possible. Otherwise at most @[nbytes] will be written.    *!
pike.git/src/modules/_Stdio/buffer.cmod:939:    *! Will return the number of bytes that were successfully written.    *!    *! If no bytes were successfully written and @expr{f->write()@} failed    *! with an error @expr{-1@} will be returned.    */    PIKEFUN int(-1..) output_to( object f, int|void _nbytes )    {    IOBuffer *io = THIS;    ssize_t written = 0, nbytes = (ssize_t)(((size_t)~0)>>1);    struct my_file *fd; -  INT_TYPE *wr = &Pike_sp->u.integer; -  +     ssize_t sz = io_len( io );       if( !sz )    {    io_range_error(io, sz);    sz = io_len(io);    }    if( _nbytes )    nbytes = _nbytes->u.integer;   
pike.git/src/modules/_Stdio/buffer.cmod:971:    continue;    if( res <= 0 ) {    fd->my_errno = errno;    if (!written) written = -1;    break;    }    io_consume( io, res );    written += res;    nbytes-=res;    } -  fd->box.revents &= ~(PIKE_BIT_FD_WRITE|PIKE_BIT_FD_WRITE_OOB); -  if(!SAFE_IS_ZERO(&fd->event_cbs[PIKE_FD_WRITE]) -  && fd->box.backend) -  set_fd_callback_events(&fd->box, fd->box.events|PIKE_BIT_FD_WRITE, 0); +  io_set_events( io, fd, PIKE_BIT_FD_WRITE_OOB, PIKE_FD_WRITE);    }    else    {    /* some other object. Just call write */    while( sz > written && nbytes)    {    size_t rd = MINIMUM(MINIMUM(sz-written,4096),nbytes); -  struct pike_string *s = io_read_string( io, rd ); -  if( !s ) -  break; -  push_string(s); -  /* when this throws we need to rewind the buffer correctly. */ -  safe_apply(f, "write", 1); -  if( *wr <= 0 ){ +  ssize_t wr = io_call_write( io, f, rd ); +  if( wr <= 0 ) +  {    io_rewind(io, rd );    if (!written) written = -1;    break;    } -  written += *wr; -  if( *wr < 4096 ) { -  io_rewind(io, rd-*wr ); +  written += wr; +  if( wr < 4096 ) { +  io_rewind(io, rd-wr );    break;    } -  pop_stack(); +     }    }    RETURN written;    }       PIKEFUN int(0..) _size_object( )    {    RETURN THIS->malloced ? THIS->allocated : 0;    }   
pike.git/src/modules/_Stdio/buffer.cmod:1106:    {    INT32 a = htonl(i);    io_append( THIS, &a, 4 );    ref_push_object(Pike_fp->current_object);    }       /*! @decl IOBuffer add_hstring( string(0..255) data, int size_size )    *! @decl IOBuffer add_hstring( Stdio.IOBuffer data, int size_size )    *! @decl IOBuffer add_hstring( System.Memory data, int size_size )    *! @decl IOBuffer add_hstring( String.Buffer data, int size_size ) +  *! @decl IOBuffer add_hstring( array data, int size_size )    *! -  *! Adds length/data for @[data] to the buffer. +  *! Adds length of data followed by @[data] to the buffer.    *! -  *! This is identical to @[sprintf("%"+size_size+"H",(string)data)] but -  *! can be significantly faster. +  *! This is identical to +  *! @code{sprintf("%"+size_size+"H",(string)Stdio.IObuffer(data))@} but +  *! significantly faster.    *! -  *! @[size_size] must be less than Int.NATIVE_MAX. +  *! @[size_size] is the number of bytes used to represent the length of the data. +  *! It must be less than Int.NATIVE_MAX. +  *! +  *! The supported @[data] argument types are +  *! +  *! @mixed +  *! @type string(0..255) +  *! An eight bit string. +  *! @type System.Memory +  *! A chunk of memory. The whole memory area is added. +  *! @type Stdio.IOBuffer +  *! A chunk of memory. The whole memory area is added. +  *! @type String.Buffer +  *! A chunk of memory. The whole memory area is added. +  *! @type array +  *! Add all elements in the array individually. Each element may be +  *! any one of the types listed here. +  *! @endmixed    */    -  PIKEFUN IOBuffer add_hstring( object str, int size_size ) +  PIKEFUN IOBuffer add_hstring( string|object|array str, int size_size )    {    IOBuffer *io = THIS; -  size_t len = io_svalue_len(io, Pike_sp-2); +  size_t len = io_svalue_len(io, str);    -  if( size_size < (int)sizeof(INT_TYPE) && +  if( size_size < (int)sizeof(size_t) &&    len > (((size_t)1)<<(8*size_size))-1 )    Pike_error("Too long string, need larger size field\n");       io_add_int( io, len, size_size ); -  io_append_svalue( io, Pike_sp-2 ); +  io_append_svalue( io, str );    pop_n_elems(args);    ref_push_object(io->this);    }    -  -  PIKEFUN IOBuffer add_hstring( string str, int size_size ) -  { -  IOBuffer *io = THIS; -  if( str->size_shift ) -  Pike_error("Only 8bit is supported\n"); -  -  /* We know this is safe for len>=4, since pike strings are at -  * most 0x7ffffff bytes long. -  */ -  if( size_size < 4 && str->len > ((INT_TYPE)1<<(8*size_size))-1 ) -  Pike_error("Too long string, need larger size field\n"); -  io_add_int( io, str->len, size_size ); -  io_append( io, str->str, str->len ); -  ref_push_object(io->this); -  } -  +     /*! @decl IOBuffer add_int( int i, int(0..) width )    *!    *! Adds a generic integer to the buffer as an (width*8)bit    *! network byteorder number.    *!    *! @[width] must be less than Int.NATIVE_MAX.    *!    */    PIKEFUN IOBuffer add_int( int i, int width )    {
pike.git/src/modules/_Stdio/buffer.cmod:1243:    if( LIKELY(TYPEOF(it[i]) == PIKE_T_INT) )    io_add_int_uc( io, it[i].u.integer, bpi);    else if( LIKELY(TYPEOF(it[i]) == PIKE_T_OBJECT) )    io_add_bignum( io, it[i].u.object, bpi );    else    Pike_error("Illegal argument.\n");    }    }    io_unset_unwrite_on_error( io, &e );    io_trigger_output( io ); -  pop_n_elems(args); +  Pike_sp--; +  pop_stack();    ref_push_object(io->this);    }       /*! @decl protected int `[](int off)    *!    *! Return the character at the specified offset.    */    PIKEFUN int(0..255) `[]( int off )    flags ID_PROTECTED;    {
pike.git/src/modules/_Stdio/buffer.cmod:1716:    push_int(0);    }    else    {    io_consume( THIS, num_used );    if( Pike_sp-start > 1 )    f_add(Pike_sp-start);    }    }    -  -  /* Used in the testsuite. -  -  It would be convenient with a 'PIKEVAR int struct.X' or something. -  */ -  PIKEFUN int(0..) `num_malloc() { RETURN THIS->num_malloc; } -  PIKEFUN int(0..) `num_move() { RETURN THIS->num_move; } -  -  +     /*! @decl void clear()    *!    *! Clear the buffer.    */    PIKEFUN void clear( )    {    IOBuffer *io = THIS;    io->offset = io->len = 0;    }   
pike.git/src/modules/_Stdio/buffer.cmod:2001:    */       INIT {    IOBuffer *this = THIS;    memset( this, 0, sizeof(IOBuffer));    this->this = Pike_fp->current_object;    }       EXIT {    IOBuffer *this = THIS; -  if( this->sub ) -  { -  free_object( this->sub ); -  io_unlock( get_storage(this->sub,IOBuffer_program ) ); -  } +  io_unlink_external_storage( this );    if( this->output )    free_object(this->output); -  if( this->source ) -  free_object( this->source ); -  if( this->str ) -  free_string( this->str ); +     if( this->error_mode )    free_program( this->error_mode );    if( this->malloced )    free( this->buffer ); -  if( this->stash.ptr ) +     free(this->stash.ptr);    }   }      void init_stdio_buffer(void)   {    INIT    start_new_program();    low_inherit(generic_error_program,0,0,0,0,0);    add_integer_constant( "buffer_error", 1, 0 );