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

version» Context lines:

pike.git/src/modules/_Stdio/buffer.cmod:6:      #include "global.h"   #include "fdlib.h"   #include "pike_netlib.h"   #include "object.h"   #include "interpret.h"   #include "operators.h"   #include "bignum.h"   #include "sscanf.h"   #include "builtin_functions.h" - #include "interpret.h" +    #include "cyclic.h"   #include "backend.h"   #include "fd_control.h"   #include "file_machine.h"   #include "file.h"   #include "whitespace.h"   #include "pike_types.h"   #include "pike_threadlib.h"   #include "buffer.h"   #include "module_support.h"   #include "bitvector.h" -  - /* Includes <gmp.h> */ - #include "bignum.h" + #include "pike_search.h"   #include "sprintf.h"      #ifdef HAVE_ARPA_INET_H   #include <arpa/inet.h>   #endif /* HAVE_ARPA_INET_H */    -  + #define READ_CHUNKSIZE 32768 + #define WRITE_CHUNKSIZE 32768 +    #define DEFAULT_CMOD_STORAGE static   DECLARATIONS      struct sysmem {    unsigned char *p;    size_t size;   };      static struct program *buffer_error_program;   
pike.git/src/modules/_Stdio/buffer.cmod:122:       static void io_ensure_unlocked(Buffer *io)    {    if( io->locked )    io_was_locked( );    }       PMOD_EXPORT void io_trim( Buffer *io )    ATTRIBUTE((noinline));    +  static void io_trim_waste( Buffer *io ) +  { +  if( UNLIKELY(io->allocated > (io_len(io) * (1.0+io->max_waste))) ) +  io_trim(io); +  } +     static int io_is_whitespace( Buffer *io, size_t pos )    {    if( pos > io_len( io ) )    return -1;    switch( io->buffer[io->offset+pos] )    {    SPACECASE8    return 1;    }    return 0;    }    -  PMOD_EXPORT void io_trim( Buffer *io ) +  static void io_discard_bufstart( Buffer *io )    { -  if( io->malloced && (io->offset > 64 || io->len > 64) && !io->locked) +  if ( LIKELY(!io->locked_move) )    { -  if( io->offset > 64 && (!io->locked_move && (io->offset > io_len(io)))) -  { +     memmove( io->buffer, io_read_pointer(io), io_len(io) );    io->len -= io->offset;    io->num_move++;    io->offset = 0;    } -  +  } +  +  PMOD_EXPORT void io_trim( Buffer *io ) +  { +  if( io->malloced && (io->offset > 64 || io->len > 64) && !io->locked) +  { +  if( io->offset > 64 && io->offset > io_len(io) ) +  io_discard_bufstart(io); +     if( io->len > 64 && ((io->allocated > (io->len)*(1.0+io->max_waste))))    {    io->buffer = xrealloc( io->buffer, io->len );    io->num_malloc++;    io->allocated = io->len;    }    }    }       static void io_unlink_external_storage( Buffer *io )
pike.git/src/modules/_Stdio/buffer.cmod:198:    memcpy( io->buffer, old, io->len );    io_unlink_external_storage(io);    }    }       PMOD_EXPORT unsigned char *io_add_space_do_something( Buffer *io, size_t bytes, int force )    ATTRIBUTE((noclone,noinline));    PMOD_EXPORT unsigned char *io_add_space_do_something( Buffer *io, size_t bytes, int force )    {    if( bytes && io->len+bytes < io->len ) -  Pike_error("Too large buffer, can not have more than %lu bytes", +  Pike_error("Too large buffer, can not have more than %lu bytes.",    (size_t)-1);          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    * (io_len(io)) and the bytes added is large and there is an    * offset, it makes sense to move now when we do not have to copy    * as much.    *    */ -  if( LIKELY(!io->locked_move) ) +  if( UNLIKELY((force && io->offset) +  || (io_len(io) && io->offset > io->allocated / 2)) )    { -  if( UNLIKELY((force && io->offset) || (io->offset > io->len)) ) -  { +     /* more than 50% of the buffer is available before the read pointer,    * and we can discard that data. Move the data to the beginning, making    * room for more data.    */ -  memmove( io->buffer, io_read_pointer(io), io_len(io) ); -  io->num_move++; -  io->len -= io->offset; -  io->offset = 0; +  io_discard_bufstart(io);    } -  } +        if( UNLIKELY(io->len + bytes > io->allocated) )    {    /* Actually grow the buffer. */    size_t growth =    (io->allocated>>1) +    (io->allocated>>3);/* io->allocated * 0.625 */       if( growth < bytes )    growth = bytes + (bytes>>1);       if( io->allocated + growth < io->allocated )    {    growth = bytes+1;    if( io->allocated + growth < io->allocated ) -  Pike_error("Overflow in buffer size calculations\n"); +  Pike_error("Overflow in buffer size calculations.\n");    }    io->buffer = xrealloc( io->buffer, io->allocated + growth );    io->num_malloc++;    io->allocated += growth;    }    return io->buffer+io->len;    }       /*! @decl protected bool range_error( int howmuch )    *!
pike.git/src/modules/_Stdio/buffer.cmod:335:       static void io_do_rewind_on_error( struct rewind_to *e )    {    e->io->locked_move--;    e->io->offset = e->rewind_to;    free( e );    }       static void io_rewind_on_error( Buffer *io, ONERROR *x )    { -  struct rewind_to *rew = xalloc( sizeof( struct rewind_to ) ); +  struct rewind_to *rew = ALLOC_STRUCT( rewind_to );    io->locked_move++;   #if defined(PIKE_DEBUG)    rew->old_locked_move = io->locked_move;   #endif    rew->io = io;    rew->rewind_to = io->offset;    SET_ONERROR( (*x), io_do_rewind_on_error, rew );    }       static void io_unset_rewind_on_error( Buffer *io, ONERROR *x )
pike.git/src/modules/_Stdio/buffer.cmod:365:    }       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( Buffer *io, ONERROR *x )    { -  struct rewind_to *rew = xalloc( sizeof( struct rewind_to ) ); +  struct rewind_to *rew = ALLOC_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( Buffer *UNUSED(io), ONERROR *x )    {    UNSET_ONERROR( (*x) );    free( x->arg );    }
pike.git/src/modules/_Stdio/buffer.cmod:430:    {    io_rewind( io, bytes-l );    }    }    io->locked_move--;    return l;    }    return -1;    }    -  static ptrdiff_t io_actually_trigger_output( Buffer *io ) +  PMOD_EXPORT ptrdiff_t io_actually_trigger_output( Buffer *io )    ATTRIBUTE((noclone,noinline));    -  static ptrdiff_t io_actually_trigger_output( Buffer *io ) +  PMOD_EXPORT ptrdiff_t io_actually_trigger_output( Buffer *io )    {    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;
pike.git/src/modules/_Stdio/buffer.cmod:460:    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;    return 0;    }    else    return io_call_write( io, &io->output, MINIMUM( io_len(io), 100 ) );    }    -  static ptrdiff_t io_trigger_output( Buffer *io ) -  { -  if( UNLIKELY(io->output.u.object) && UNLIKELY(!io->output_triggered) ) -  return io_actually_trigger_output(io); -  return 0; -  } -  +     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;       push_int64( howmuch );    apply_current( f_Buffer_range_error_fun_num, 1 );
pike.git/src/modules/_Stdio/buffer.cmod:557:    return end_shared_string(s);    }       static struct object *io_read_buffer( Buffer *io, size_t len, int do_copy )    {    struct object *b;    Buffer *to;    if( !io_avail(io,len))    return NULL;    -  b = low_clone( Buffer_program ); +  b = fast_clone_object( Buffer_program );    to = get_storage(b,Buffer_program);       io_lock( io );       to->buffer = io_read_pointer(io);    to->len = len;    to->sub = Pike_fp->current_object;    add_ref(to->sub);    io_consume( io, len );   
pike.git/src/modules/_Stdio/buffer.cmod:589:    static INT_TYPE io_read_number_uc( Buffer *io, size_t len )    {    INT_TYPE res = 0;    while( LIKELY(len--) ) {    res <<= 8;    res |= io_read_byte_uc(io);    }    return res;    }    +  static INT_TYPE io_read_le_number_uc( Buffer *io, size_t len ) +  { +  INT_TYPE res = 0; +  size_t i; +  for(i=0; i<len; i++) +  res |= (io_read_byte_uc(io) << i*8); +  return res; +  } +     static INT_TYPE io_read_signed_number_uc( Buffer *io, size_t len )    {    INT_TYPE res = 0;    if( LIKELY(len--) ) {    res = (INT8)io_read_byte_uc(io);    while( LIKELY(len--) ) {    res <<= 8;    res |= io_read_byte_uc(io);    }    }    return res;    }    -  static INT64 io_read_number( Buffer *io, size_t len ) +  static INT64 io_read_number( Buffer *io, size_t len, int endian )    {    INT64 res;    if( !io_avail(io, len) )    return -1;    /* ensure only leading 0:s */    for (; UNLIKELY(len > SIZEOF_INT_TYPE); len--)    if( UNLIKELY(io_read_byte_uc(io)) )    Pike_error("Integer (%dbit) overflow.\n", SIZEOF_INT_TYPE*8);    -  +  /* NB: endian == 0 for little endian, +  * 1 for big endian. +  */ +  if( endian )    res = io_read_number_uc( io, len ); -  +  else +  res = io_read_le_number_uc( io, len );       if ( UNLIKELY(res < 0) )    Pike_error("Signed (%dbit) overflow.\n", SIZEOF_INT_TYPE*8);    return res;    }    -  static struct object *io_read_bignum( Buffer *io, size_t len ) +  static struct object *io_read_bignum( Buffer *io, size_t len, int endian )    {    struct object *o;    MP_INT *i;    unsigned char *p;       if( !io_avail(io,len) ) return NULL;    o = fast_clone_object(bignum_program);    i = (void*)o->storage; -  mpz_import( i, len, 1, 1, 0, 0, io_read_pointer(io) ); +  /* NB: endian == -1 for little endian, +  * 0 for native, +  * 1 for big endian. +  */ +  mpz_import( i, len, endian, 1, endian, 0, io_read_pointer(io) );    io_consume(io,len);    return o;    }       static void io_add_bignum( Buffer *io, struct object *o, int width )    ATTRIBUTE((noclone,noinline));       static void io_add_bignum( Buffer *io, struct object *o, int width )    {    MP_INT *i = (void*)o->storage;
pike.git/src/modules/_Stdio/buffer.cmod:658:    {    mpz_init( &tmp );    mpz_add_ui( &tmp, i, 1);    pad = 0xff;    i = &tmp;    }       bytes = (mpz_sizeinbase( i, 2 )+7) / 8;       if( bytes > width ) -  Pike_error("Number too large to store in %d bits\n", width*8); +  Pike_error("Number too large to store in %d bits.\n", width*8);       d = io_add_space( io, width, 0 );    io->len += width;       if( width > bytes )    {    memset( d, pad, width-bytes );    d += width-bytes;    }   
pike.git/src/modules/_Stdio/buffer.cmod:687:    Pike_fatal("Oddities abound\n");   #endif    *d = pad;    }    if( pad )    {    while(exp--)    *d++ ^= 0xff; /* pad, but that is 0xff */    mpz_clear(&tmp);    } +  io_trigger_output( io );    }       static void io_add_int_uc( Buffer *io, ptrdiff_t i, size_t bytes )    {    unsigned char *x = io->buffer+io->len;    io->len += bytes;    while(bytes--)    {    x[bytes] = i;    i>>=8;
pike.git/src/modules/_Stdio/buffer.cmod:772:    END_CYCLIC();    return len;    }    case PIKE_T_OBJECT: {    size_t len;    if( get_memory_object_memory( p->u.object, NULL, &len, NULL ) )    return len;    break;    }    } -  Pike_error("Illegal argument (not an 8bit string or 8bit buffer object)\n"); +  Pike_error("Illegal argument (not an 8bit string or 8bit 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( 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("Too big bignum, can not fit in indicated width.\n");    } -  Pike_error("Non integer argument\n"); +  Pike_error("Non integer argument.\n");    }       static void io_append_svalue( Buffer *io, struct svalue *p )    ATTRIBUTE((noinline));       static void io_append_svalue( Buffer *io, struct svalue *p )    {    switch( TYPEOF(*p) )    {    case PIKE_T_STRING:    {    struct pike_string *s = p->u.string;    if( !s->len ) return; -  if( s->size_shift ) Pike_error("Buffer only handles 8bit data\n"); +  if( s->size_shift ) Pike_error("Buffer only handles 8bit data.\n");    if( !io->buffer )    {   #ifdef PIKE_DEBUG    if (io->str) Pike_fatal("Buffer with string but NULL buffer.\n");   #endif    io->str = s;    io->buffer = (unsigned char*)s->str;    io->len = s->len;    add_ref(s);    io_trigger_output( io );
pike.git/src/modules/_Stdio/buffer.cmod:855:    io->buffer = ptr;    io->len = len;       io->source = p->u.object;    add_ref(io->source);    return;    }    if( t != MEMOBJ_NONE )    io_append( io, ptr, len );    else -  Pike_error("Unsupported argument type\n"); +  Pike_error("Unsupported argument type.\n");    }    break;    case PIKE_T_INT:    {    unsigned char a = p->u.integer;    io_append( io, &a, 1 );    }    }    }   
pike.git/src/modules/_Stdio/buffer.cmod:904:    if (!nbytes) RETURN 0;    }       if( _once )    once = _once->u.integer;       if( (fd = get_storage( f, file_program )) )    {    while( 1 )    { -  unsigned char *ptr = io_add_space( io, 4096, 0 ); +  unsigned char *ptr = io_add_space( io, READ_CHUNKSIZE, 0 );    int res;    -  res = fd_read( fd->box.fd, ptr, MINIMUM(4096,nbytes) ); +  res = fd_read( fd->box.fd, ptr, MINIMUM(READ_CHUNKSIZE, nbytes) );       if( res == -1 && errno == EINTR )    continue;       if( res <= 0 )    break;       nbytes -= res;    io->len += res;    bread += res; -  if( res != 4096 || once || !nbytes ) +  if( res != READ_CHUNKSIZE || once || !nbytes )    break;    }    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) ); +  push_int( MINIMUM(READ_CHUNKSIZE, nbytes) );    safe_apply( f, "read", 1 );    if( TYPEOF(Pike_sp[-1]) != PIKE_T_STRING || Pike_sp[-1].u.string->len == 0 )    break;    if( Pike_sp[-1].u.string->size_shift ) -  Pike_error("Can not handle non-8bit data\n"); +  Pike_error("Can not handle non-8bit data.\n");    io_append( io, Pike_sp[-1].u.string->str, Pike_sp[-1].u.string->len );    nbytes -= Pike_sp[-1].u.string->len;    pop_stack();    }    }       if (!bread) RETURN -1;    -  +  io_trigger_output( io ); +     RETURN bread;    }       /*! @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.
pike.git/src/modules/_Stdio/buffer.cmod:1049:    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) &&    (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); +  ptrdiff_t rd = MINIMUM(sz-written, WRITE_CHUNKSIZE);    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;    }
pike.git/src/modules/_Stdio/buffer.cmod:1071:    written += res;    io_set_events( io, fd, PIKE_BIT_FD_WRITE_OOB, PIKE_FD_WRITE);    }    RETURN written;    }    }       /* Some other object or function. Just call it. */    while( sz > written )    { -  size_t rd = MINIMUM(sz-written,4096); +  size_t rd = MINIMUM(sz-written, WRITE_CHUNKSIZE);    ptrdiff_t wr = io_call_write( io, f, rd );    if( wr <= 0 )    {    if (!written) written = -1;    break;    }    written += wr; -  if( wr < 4096 ) +  if( wr < WRITE_CHUNKSIZE )    break;    }    RETURN written;    }       /*! @decl int(-1..) try_output()    *!    *! Try to write some data from the buffer to the file    *! registered with @[__fd_set_output()].    *!
pike.git/src/modules/_Stdio/buffer.cmod:1110:    PIKEFUN int(-1..) try_output()    {    Buffer *io = THIS;    if (LIKELY(io->output.u.object) && LIKELY(!io->output_triggered))    RETURN io_actually_trigger_output(io);    RETURN 0;    }       /*! @decl int read_sint( int size )    *! -  *! Read a network byte order two:s complement signed number of size n*8 bits, then -  *! return it. +  *! 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.    */    PIKEFUN int read_sint( int nbytes )    {    Buffer *io = THIS;    struct pike_string *tmp;    Pike_sp--;    if( !io_avail( io, nbytes ) )
pike.git/src/modules/_Stdio/buffer.cmod:1151:    ref_push_string( tmp );    push_int( 256 );    push_object( clone_object( bignum_program, 2 ) );    if( tmp->str[0]&0x80 )    o_xor();    free_string( tmp );    }       PIKEFUN int(0..) _size_object( )    { -  RETURN THIS->malloced ? THIS->allocated : 0; +  Buffer *io = THIS; +  if (io->malloced) +  { +  push_ulongest(THIS->allocated);    } -  +  else +  { +  push_int(0); +  } +  }       /*! @decl Buffer add_padding( int(0..) nbytes, int(0..255)|void byte )    *!    *! Add @[nbytes] bytes of padding, if @[byte] is not specified the    *! area will be filled with 0's, otherwise the specified byte will    *! be repeated.    */    PIKEFUN Buffer add_padding( int(0..) nbytes, int|void _byte )    {    Buffer *io = THIS;    int byte = 0;    if( _byte ) byte = _byte->u.integer;       if( nbytes < 0 )    Pike_error("Cannot add negative padding.\n");       memset( io_add_space( io, nbytes,0), byte, nbytes );    io->len += nbytes;    Pike_sp -= args; -  +  io_trigger_output( io );    ref_push_object( io->this );    }       /*! @decl Buffer add( AddArgument ... data )    *! @code    *! private typedef @[System.Memory]|@[Stdio.Buffer]|@[String.Buffer] BufferObject;    *! private typedef BufferObject|string(8bit)|int(8bit)|array(AddArgument) AddArgument;    *! @endcode    *!    *! Add the items in data to the end of the buffer.
pike.git/src/modules/_Stdio/buffer.cmod:1227:       /*! @decl Buffer add_int8( int(8bit) )    *! Adds a single byte to the buffer.    */    PIKEFUN Buffer add_int8( int i )    {    Buffer *io = THIS;    *io_add_space(io,1,0)=i;    io->len++;    Pike_sp--; +  io_trigger_output( io );    ref_push_object(Pike_fp->current_object);    }    -  +  /*! @decl Buffer add_int8( Gmp.mpz ) +  *! Adds a single byte to the buffer. +  */ +  PIKEFUN Buffer add_int8( object mpz ) +  { +  INT64 i = 0; +  Buffer *io = THIS; +  unsigned char *p = io_add_space(io,1,0); +  if (!low_int64_from_bignum(&i, mpz)) { +  SIMPLE_ARG_TYPE_ERROR("add_int8", 1, "int|Gmp.mpz"); +  } +  *p = i; +  io->len++; +  ref_push_object(Pike_fp->current_object); +  } +     /*! @decl Buffer add_int16( int(16bit) )    *!    *! Add a 16-bit network byte order value to the buffer    */    PIKEFUN Buffer add_int16( int i )    {    Buffer *io = THIS;    unsigned char *p = io_add_space(io,2,0);    p[0] = i>>8;    p[1] = i;    io->len += 2; -  +  io_trigger_output( io );    ref_push_object(Pike_fp->current_object);    }    -  +  /*! @decl Buffer add_int16( Gmp.mpz ) +  *! +  *! Add a 16-bit network byte order value to the buffer +  */ +  PIKEFUN Buffer add_int16( object mpz ) +  { +  INT64 i = 0; +  Buffer *io = THIS; +  unsigned char *p = io_add_space(io,2,0); +  if (!low_int64_from_bignum(&i, mpz)) { +  SIMPLE_ARG_TYPE_ERROR("add_int16", 1, "int|Gmp.mpz"); +  } +  p[0] = i>>8; +  p[1] = i; +  io->len += 2; +  ref_push_object(Pike_fp->current_object); +  } +     /*! @decl Buffer add_int32( int i )    *! Adds a 32 bit network byte order value to the buffer    */    PIKEFUN Buffer add_int32( int i )    {    Buffer *io = THIS;    unsigned char *p = io_add_space(io,4,0);    p[0] = i>>24;    p[1] = i>>16;    p[2] = i>>8;    p[3] = i;    io->len += 4; -  +  io_trigger_output( io );    ref_push_object(Pike_fp->current_object);    }       /*! @decl Buffer add_int32( Gmp.mpz i )    *! Adds a 32 bit network byte order value to the buffer    */    PIKEFUN Buffer add_int32( object mpz )    {    INT64 i = 0;    Buffer *io = THIS;    unsigned char *p = io_add_space(io,4,0); -  if (!int64_from_bignum(&i, mpz)) { +  if (!low_int64_from_bignum(&i, mpz)) {    SIMPLE_ARG_TYPE_ERROR("add_int32", 1, "int|Gmp.mpz");    }    p[0] = i>>24;    p[1] = i>>16;    p[2] = i>>8;    p[3] = i;    io->len += 4; -  +  io_trigger_output( io );    ref_push_object(Pike_fp->current_object);    }       /*! @decl Buffer add_hstring( string(8bit) data, int size_size )    *! @decl Buffer add_hstring( Stdio.Buffer data, int size_size )    *! @decl Buffer add_hstring( System.Memory data, int size_size )    *! @decl Buffer add_hstring( String.Buffer data, int size_size )    *! @decl Buffer add_hstring( int(8bit) data, int size_size )    *! @decl Buffer add_hstring( array data, int size_size )    *! @decl Buffer add_hstring( int|string(8bit)|Stdio.Buffer|System.Memory|array data, int size_size, int offset )
pike.git/src/modules/_Stdio/buffer.cmod:1336:    int size_size, void|int offset )    {    Buffer *io = THIS;    size_t len = io_svalue_len(io, str);       if( offset )    len += offset->u.integer;       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"); +  Pike_error("Too long string, need larger size field.\n");       io_add_int( io, len, size_size );    io_append_svalue( io, str );    pop_n_elems(args);    ref_push_object(io->this);    }       /*! @decl Buffer add_int( int i, int(0..) width )    *!    *! Adds a generic integer to the buffer as an (width*8)bit
pike.git/src/modules/_Stdio/buffer.cmod:1432:    int i,l = a->size;    struct svalue *it = a->item;    unsigned char *ptr;    ptrdiff_t n=0;    ONERROR e;    Buffer *io = THIS;       io_unwrite_on_error(io, &e);       if( bpi < 0 ) -  Pike_error("Illegal int width\n"); +  Pike_error("Illegal int width.\n");      #if SIZEOF_LONG == 4    if( DO_INT32_MUL_OVERFLOW( l, bpi, &n ) )   #else    if( DO_INT64_MUL_OVERFLOW( l, bpi, &n ) )   #endif -  Pike_error("Result size exceeds ptrdiff_t size\n"); +  Pike_error("Result size exceeds ptrdiff_t size.\n");       io_add_space( io, n, 0 );    switch( bpi )    {    case 1:    for( i=0; i<l; i++ )    io_append_byte_uc( io, get_small_int(it+i) );    break;    case 2:    for( i=0; i<l; i++ )
pike.git/src/modules/_Stdio/buffer.cmod:1485:    Pike_error("Illegal argument.\n");    }    }    io_unset_unwrite_on_error( io, &e );    io_trigger_output( io );    Pike_sp--;    pop_stack();    ref_push_object(io->this);    }    -  /*! @decl protected int `[](int off) +  /*! @decl protected int(-1..255) `[](int off)    *!    *! Return the character at the specified offset. -  +  *! +  *! @returns +  *! Returns the character at offset @[off] on success, +  *! and @expr{-1@} otherwise.    */    PIKEFUN int(8bit) `[]( int off )    flags ID_PROTECTED;    {    Buffer *io = THIS;    if( off < 0 )    off = io_len(io)-off;       if( io_avail( io, off ) )    Pike_sp[-1].u.integer = io_read_pointer(io)[off];    else    Pike_sp[-1].u.integer = -1;    }    -  /*! @decl protected int `[]=(int off, int char) +  /*! @decl protected void `[]=(int off, int char)    *!    *! Set the character at the specified offset to @[char].    */ -  PIKEFUN int(8bit) `[]=( int off, int val ) +  PIKEFUN void `[]=( int off, int val )    flags ID_PROTECTED;    {    Buffer *io = THIS;       io_ensure_malloced( io, 0 );       if( off < 0 ) off = io_len(io)-off;    again:    if( io_avail( io, off ) )    {    io_read_pointer(io)[off]=(val&0xff);    }    else    {    /* hm, well. We could extend the buffer. Should we? */    if( io_range_error(io, off ) )    goto again; -  Pike_error("Writing outside buffer\n"); +  Pike_error("Writing outside buffer.\n");    }    }       /*! @decl int _sizeof()    *!    *! Returns the buffer size, in bytes.    *! This is how much you can read from the buffer until it runs out of data.    */    PIKEFUN int(0..) _sizeof()    flags ID_PROTECTED;    { -  push_int64(io_len(THIS)); +  push_ulongest(io_len(THIS));    }       /*! @decl string cast(string type)    *!    *! Convert the buffer to a string.    *!    *!@note    *! This only works for buffers whose length is less than 0x7fffffff.    */    PIKEFUN string(8bit) cast(string to)
pike.git/src/modules/_Stdio/buffer.cmod:1709:    *! Note that pike string can not be longer than 0x7fffffff bytes (~2Gb).    */    PIKEFUN string(8bit) read_hstring( int bytes, void|int offset )    {    INT64 len;    Buffer *io = THIS;    struct pike_string *s;    ONERROR e;       io_rewind_on_error( io, &e ); -  len = io_read_number( io, bytes ); +  len = io_read_number( io, bytes, 1 );       if (offset)    len -= offset->u.integer;       if (len < 0) {    /* io_avail() in io_read_number() failed. */    CALL_AND_UNSET_ONERROR(e);    Pike_sp[-1].u.integer = 0;    return;    }
pike.git/src/modules/_Stdio/buffer.cmod:1734:    if( s ) {    io_unset_rewind_on_error( io, &e );    Pike_sp--;    push_string(s);    } else {    CALL_AND_UNSET_ONERROR(e);    Pike_sp[-1].u.integer = 0;    }    }    -  /*! @decl string(8bit) read_cstring(void|int sentinel) +  /*! @decl string(8bit) read_cstring(void|int(8bit) sentinel, @ +  *! void|int(8bit) escape)    *!    *! Reads a \0 terminated C-string and returns the    *! string excluding the terminating \0.    *!    *! If there is not enough data available return UNDEFINED.    *!    *! Note that pike string can not be longer than 0x7fffffff bytes (~2Gb).    *!    *! @param sentinel -  *! A different character can be used as end sentinel of the string. +  *! A different character can be used as end sentinel of the string.    *! -  +  *! @param escape +  *! An optional character used as a prefix to quote the following +  *! character. UNDEFINED and the same value as @[sentinel] mean +  *! that there is no escape character. +  *! +  *! @note +  *! Escape characters (if any) are left untouched in the returned string. +  *!    *! @seealso    *! @[_search()]    */ -  PIKEFUN string(8bit) read_cstring(void|int sentinel) +  PIKEFUN string(8bit) read_cstring(void|int(8bit) sentinel, +  void|int(8bit) escape)    { -  INT64 len; +     Buffer *io = THIS; -  struct pike_string *s; -  ONERROR e; -  int end = 0; -  if( sentinel ) -  end = sentinel->u.integer; +  int csentinel = sentinel ? sentinel->u.integer : 0;    -  io_rewind_on_error( io, &e ); -  len = 0; +  if (!escape || (escape->u.integer == csentinel)) {    do { -  /* search the amount of data we know we have for each call to io_avail */ -  while( io_len(io) ) +  if ( LIKELY(io_len(io)) )    { -  if( io_read_byte_uc(io)==end ) -  goto found_end; -  len++; +  const char * start = (char*)io_read_pointer(io); +  const char * end = memchr(start, csentinel, io_len(io)); +  +  if ( LIKELY(end) ) +  { +  push_string(io_read_string(io, end - start)); +  io_read_byte_uc(io); /* consume the terminating sentinel byte */ +  return;    }    } -  while( io_avail( io, 1 ) ); +  } while ( UNLIKELY(io_range_error(io, 0)) ); +  } else { +  int cescape = escape->u.integer; +  do { +  if ( LIKELY(io_len(io)) ) +  { +  const char * start = (char*)io_read_pointer(io); +  const char * end = memchr(start, csentinel, io_len(io)); +  +  if ( LIKELY(end) ) +  { +  /* Check if we have any escaped characters. */ +  const char * esc = start; +  while (UNLIKELY(esc = memchr(esc, cescape, end - esc))) { +  esc += 2; +  if (end + 1 == esc) { +  /* NB: The following is integer underflow safe; +  * Worst case: end = start + io_len(io) - 1. +  * ==> esc = start + io_len(io). +  * ==> start + io_len - esc == 0. +  */ +  end = memchr(esc, csentinel, start + io_len(io) - esc); +  if (UNLIKELY(!end)) {    goto fail; -  +  } +  } +  } +  push_string(io_read_string(io, end - start)); +  io_read_byte_uc(io); /* consume the terminating sentinel byte */ +  return; +  } +  } +  fail: +  ; /* NB: Some C-compilers require a statement after a label. */ +  } while ( UNLIKELY(io_range_error(io, 0)) ); +  }    -  found_end: -  io_rewind( io, len+1 ); -  s = io_read_string( io, len ); -  -  if( LIKELY(s) ) { -  io_read_byte_uc(io); /* consume the terminating byte */ -  io_unset_rewind_on_error( io, &e ); -  push_string(s); -  } else { - fail: CALL_AND_UNSET_ONERROR(e); +     push_undefined();    } -  } +        /*! @decl protected int(-1..) _search(int(8bit) character, int|void start, @    *! int|void end)    *!    *! Search forward from the indicated @[start] position for the specified    *! @[character].    *!    *! @param character    *! Character to search for.    *!
pike.git/src/modules/_Stdio/buffer.cmod:1971:    INT64 len;    int do_copy = 0;    Buffer *io = THIS;    ONERROR e;       io_rewind_on_error( io, &e );       if( copy ) do_copy = copy->u.integer;    Pike_sp-=args;    -  len = io_read_number( io, bytes ); +  len = io_read_number( io, bytes, 1 );    if( len >= 0 && io_avail( io, len ) )    {    push_object( io_read_buffer( io, len, do_copy ) );    io_unset_rewind_on_error( io, &e );    return;    }    CALL_AND_UNSET_ONERROR(e);    push_int(0);    }   
pike.git/src/modules/_Stdio/buffer.cmod:2027:    PIKEFUN Buffer sprintf(mixed ... ignored)    rawtype tFuncV(tAttr("strict_sprintf_format", tOr(tStr, tObj)),    tAttr("sprintf_args", tMix), tObjIs_BUFFER);    {    ONERROR _e;    struct string_builder tmp;    init_string_builder(&tmp,0);    SET_ONERROR(_e, free_string_builder, &tmp);    low_f_sprintf(args, &tmp);    if( tmp.s->size_shift ) -  Pike_error("Buffer only handles 8bit data\n"); +  Pike_error("Buffer only handles 8bit data.\n");    io_append( THIS, tmp.s->str, tmp.s->len );    pop_n_elems(args);    CALL_AND_UNSET_ONERROR(_e);    ref_push_object(Pike_fp->current_object);    }       /*! @decl array sscanf(string(8bit) format)    *!    *! Reads data from the beginning of the buffer to match the    *! specifed format, then return an array with the matches.
pike.git/src/modules/_Stdio/buffer.cmod:2091:    *!    *! @note    *! Unless whitespaces are required this function only really work correctly    *! with objects, arrays and strings.    *!    *! There is really no way to see where one value starts and the other ends    *! for most other cases    */    PIKEFUN mixed read_json(int|void require_whitespace)    { -  int stop, whites = 0; +  INT_TYPE whites = 0; +  ptrdiff_t stop;    static ptrdiff_t(*parse_json_pcharp)(PCHARP,size_t,int,char**);    char *err = NULL;    if( require_whitespace )    whites = require_whitespace->u.integer;       Pike_sp-=args;    if( !parse_json_pcharp )    parse_json_pcharp = PIKE_MODULE_IMPORT(Standards.JSON, parse_json_pcharp );    retry:    stop = parse_json_pcharp( MKPCHARP(io_read_pointer(THIS),0),
pike.git/src/modules/_Stdio/buffer.cmod:2116:    if( -stop == (ptrdiff_t)io_len(THIS) || (err && !strncmp(err,"Unterminated",12)))    {    if( io_range_error(THIS,0) )    goto retry;    push_undefined();    }    else    {    /* FIXME: Use real json error? */    if( err ) -  Pike_error("Syntax error in json at offset %d: %s\n", -stop, err ); +  Pike_error("Syntax error in json at offset %d: %s,\n", -stop, err );    else -  Pike_error("Syntax error in json at offset %d\n", -stop ); +  Pike_error("Syntax error in json at offset %d.\n", -stop );    }    }    else    {    if( whites &&    (io_is_whitespace(THIS,stop)<=0 && io_is_whitespace(THIS,stop-1)<=0))    {    if( stop == (ptrdiff_t)io_len(THIS) )    {    if( io_range_error(THIS,0) )    goto retry;    pop_stack();    push_undefined();    }    else -  Pike_error("Missing whitespace between json values at offset %d\n", stop ); +  Pike_error("Missing whitespace between json values at offset %d.\n", stop );    }    else    {    if( whites )    while( io_is_whitespace( THIS, stop ) )    stop++;    io_consume( THIS, stop );    }    }    }
pike.git/src/modules/_Stdio/buffer.cmod:2212:    *! factor of the current buffer size.    *!    *! The default is 0.5, leaving at most half the buffer as waste.    *!    */    PIKEFUN void set_max_waste(float howmuch)    {    Buffer *io = THIS;    io->max_waste = howmuch;    io_add_space( io, 0, 1 ); -  io_consume( io, 0 ); +  io_trim_waste( io );    }       /*! @decl void trim()    *!    *! Frees unused memory.    *!    *! Note that calling this function excessively will slow things    *! down, since the data often has to be copied.    *!    *! @note
pike.git/src/modules/_Stdio/buffer.cmod:2234:    *! if the realloc fails to find a new (smaller) memory area.    */    PIKEFUN void trim( )    {    Buffer *io = THIS;       io_add_space( io, 0, 1 );    io_trim(io);    }    +  /*! @decl void allocate( int(0..) n ) +  *! +  *! Make sure that at least @[n] bytes of space are available in this buffer. +  */ +  PIKEFUN void allocate( int n ) +  { +  Buffer *io = THIS; +  Pike_sp--; +  if (!n) return; +  if (n < 0) +  SIMPLE_BAD_ARG_ERROR("allocate()", 1, "int(0..1)"); +  io_add_space(io, n, 0); +  } +     /*! @decl int(0..)|int(-1..-1) consume( int(0..) n )    *!    *! Discard the first @[n] bytes from the buffer    *!    *! Returns -1 on error and the amount of space still left otherwise.    */    PIKEFUN int(-1..) consume( int n )    {    Pike_sp--;    if( !io_avail( THIS, n ) )
pike.git/src/modules/_Stdio/buffer.cmod:2293:    *! You can call @[unread(0)] to see how much.    */    PIKEFUN int(-1..) unread( int bytes )    {    Pike_sp--;    push_int64( io_rewind( THIS, bytes ) );    }       /*! @decl string(8bit) read( int n )    *! -  *! Read @[bytes] bytes of data from the buffer. +  *! Read @[n] bytes of data from the buffer.    *!    *! If there is not enough data available this returns 0.    *!    *! @seealso    *! @[try_read()]    */    PIKEFUN string(8bit) read( int bytes )    {    struct pike_string *s;    Pike_sp--;
pike.git/src/modules/_Stdio/buffer.cmod:2400:    {    Buffer *io = THIS;    if( LIKELY(io_avail( io, 4 )) )    {    push_int( io_read_number_uc(io,4) );   #if SIZEOF_INT_TYPE < 5    if( UNLIKELY(Pike_sp[-1].u.integer < 0) )    {    io_rewind( io, 4 );    pop_stack(); -  push_object( io_read_bignum(io, 4) ); +  push_object( io_read_bignum(io, 4, 1) );    }   #endif    }    else    push_int(-1);    }       /*! @decl int read_int( int n )    *!    *! Read a network byte order unsigned number of size n*8 bits, then    *! return it.    *!    *! Will return -1 if there is not enough buffer space available    *! unless error mode is set to throw errors. -  +  *! +  *! @seealso +  *! @[read_le_int]    */    PIKEFUN int(0..) read_int( int len )    {    Buffer *io = THIS;    struct object *o;       Pike_sp--;    -  if( len < SIZEOF_INT_TYPE-1 ) /* will for sure fit. */ +  if( len < SIZEOF_INT_TYPE ) /* will for sure fit. */    { -  push_int( io_read_number( io, len ) ); +  push_int( io_read_number( io, len, 1 ) );    return;    }    -  if( (o = io_read_bignum(io, len )) ) +  if( (o = io_read_bignum(io, len, 1)) )    {    push_object(o);    reduce_stack_top_bignum();    return;    }    push_int(-1);    }    -  +  /*! @decl int read_le_int( int n ) +  *! +  *! Read a big endian byte order unsigned number of size n*8 bits, +  *! then return it. +  *! +  *! Will return -1 if there is not enough buffer space available +  *! unless error mode is set to throw errors. +  *! +  *! @seealso +  *! @[read_int] +  */ +  PIKEFUN int(0..) read_le_int( int len ) +  { +  Buffer *io = THIS; +  struct object *o; +  +  Pike_sp--; +  +  if( len < SIZEOF_INT_TYPE ) /* will for sure fit. */ +  { +  push_int( io_read_number( io, len, 0 ) ); +  return; +  } +  +  if( (o = io_read_bignum(io, len, -1)) ) +  { +  push_object(o); +  reduce_stack_top_bignum(); +  return; +  } +  push_int(-1); +  } +     /*! @decl int read_hint( int n )    *!    *! Read a network byte order unsigned number of size n*8 bits, then    *! read another network byte order number of the size indicated by    *! the first size.    *!    *! Will return -1 if there is not enough buffer space available    *! unless error mode is set to throw errors.    */    PIKEFUN int(0..) read_hint( int size_len )    {    Buffer *io = THIS;    ONERROR e;    INT_TYPE len;    struct object *o;       io_rewind_on_error( io, &e );    -  len = io_read_number( io, size_len ); +  len = io_read_number( io, size_len, 1 );    if( len >= 0 )    {    if( len < SIZEOF_INT_TYPE )    { -  if( (Pike_sp[-1].u.integer = io_read_number( io, len )) == -1 ) +  if( (Pike_sp[-1].u.integer = io_read_number( io, len, 1 )) == -1 )    goto neg_one;    } -  else if( (o = io_read_bignum( io, len )) ) +  else if( (o = io_read_bignum( io, len, 1 )) )    {    Pike_sp--;    push_object(o);    reduce_stack_top_bignum();    }    else    goto neg_one;    io_unset_rewind_on_error( io, &e );    return;    }
pike.git/src/modules/_Stdio/buffer.cmod:2513:    if( len < SIZEOF_INT_TYPE-1 ) /* will for sure fit. */    {    push_array(a = allocate_array(num));    for( i=0;i<num;i++ )    a->item[i].u.integer = io_read_number_uc( io, len );    return;    }       for( i=0; i<num; i++ )    { -  push_object(io_read_bignum( io, len )); +  push_object(io_read_bignum( io, len, 1 ));    reduce_stack_top_bignum();    }    f_aggregate(num);    }      /*! @decl string _encode()    *! @decl void _decode(string x)    *!    *! Encode and decode Stdio.Buffer objects.    *! Only the buffer data is kept, no other state is saved.
pike.git/src/modules/_Stdio/buffer.cmod:2561:    {    io_lock( THIS );    }          static struct object* io_create_rewind_key( Buffer *io, int how );       /*! @decl RewindKey rewind_on_error()    *! @decl RewindKey rewind_key()    *! -  *! These functions are very similar. The @[rewind_on_error] edition +  *! These functions are very similar. The @[rewind_on_error] variant    *! will create an object that, when it goes out of scope without    *! having been destructed explicitly, will cause the buffer to    *! rewind to the location it had when this function is called.    *!    *! This will happen if you throw an error @i{or@} otherwise let the    *! object fall out of scope.    *!    *! Use @[destruct(RewindKey)] or @[RewindKey.release] to stop the    *! buffer from being rewound.    *!
pike.git/src/modules/_Stdio/buffer.cmod:2675:    }    else if( TYPEOF(*x) == PIKE_T_INT )    {    INT_TYPE len = x->u.integer;    if( len <= 0 )    this->buffer = xalloc(1);    else    this->buffer = xalloc(len);    this->allocated = MAXIMUM(len,1);    this->malloced = 1; +  pop_stack();    }    else -  +  {    io_append_svalue( THIS, x ); -  +  pop_stack();    } -  +  }       INIT {    Buffer *this = THIS; -  memset( this, 0, sizeof(Buffer)); +     this->max_waste = 0.615;    this->this = Pike_fp->current_object;    }       EXIT {    Buffer *this = THIS;    io_unlink_external_storage( this );    if( this->error_mode )    free_program( this->error_mode );    if( this->malloced )
pike.git/src/modules/_Stdio/buffer.cmod:2744:    if( THIS->obj->prog && THIS->io )    THIS->rewind_to = THIS->io->offset;    }       EXIT {    if( THIS->io && THIS->obj->prog )    THIS->io->locked_move--;    free_object( THIS->obj );    }    -  PIKEFUN void destroy( int reason ) +  PIKEFUN void _destruct( int reason )    flags ID_PRIVATE;    {    if( reason > 1 && THIS->auto_mode ) /* no refs or gc */    {    if( THIS->io && THIS->obj->prog )    THIS->io->offset = THIS->rewind_to;    }    }       /*! @decl void rewind()