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

version» Context lines:

pike.git/src/modules/_Stdio/buffer.cmod:17:   #include "pike_types.h"   #include "pike_threadlib.h"   #include "iobuffer.h"   #include "module_support.h"      #include <arpa/inet.h>      #define DEFAULT_CMOD_STORAGE static   DECLARATIONS    +    struct sysmem {    unsigned char *p;    size_t size;   };    - static struct program *shm_program, *sbuf_program; - static struct sysmem *system_memory(struct object *o) - { -  if( !shm_program ) -  { -  push_text("System.Memory"); -  SAFE_APPLY_MASTER("resolv", 1); -  shm_program = program_from_svalue(Pike_sp - 1); -  if (!shm_program) -  return 0; -  Pike_sp--; -  } -  return get_storage( o, shm_program ); - } -  - static struct string_builder *string_buffer(struct object *o) - { -  if( !sbuf_program ) -  { -  push_text("String.Buffer"); -  SAFE_APPLY_MASTER("resolv", 1); -  sbuf_program = program_from_svalue(Pike_sp - 1); -  if (!sbuf_program) -  return 0; -  Pike_sp--; -  } -  return get_storage( o, sbuf_program ); - } -  -  +    static struct program *buffer_error_program;      /*! @module Stdio    */      /*! @class IOBuffer    *!    *! A buffer to use as input or buffering when doing I/O. It is    *! similar to @[String.Buffer], but can only contain 8bit data and is    *! designed for protocol parsing. It is optimized for reading from
pike.git/src/modules/_Stdio/buffer.cmod:110:    static void io_unlock( IOBuffer *io )    {    io->locked--;    }       static void io_lock( IOBuffer *io )    {    io->locked++;    }    -  static void io_ensure_unlocked(IOBuffer *io) +  static void io_was_locked( ) +  ATTRIBUTE((noclone,noinline)); +  +  static void io_was_locked( )    { -  if( io->locked ) +     Pike_error("Can not modify the buffer right now, "    " there are active subbuffers.\n");    }    -  +  static void io_ensure_unlocked(IOBuffer *io) +  { +  if( io->locked ) +  io_was_locked( ); +  } +     static INT_TYPE io_consume( IOBuffer *io, int num )    {    io->offset += num;    return io_len(io);    }       static unsigned char *io_read_pointer(IOBuffer *io)    {    return io->buffer + io->offset;    }
pike.git/src/modules/_Stdio/buffer.cmod:157:    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 ) +  ATTRIBUTE((noclone,noinline)); +  +  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.
pike.git/src/modules/_Stdio/buffer.cmod:214:    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 );    io_unlink_external_storage(io);    }    }    }    -  static unsigned char *io_add_space( IOBuffer *io, int bytes, int force ) +  static unsigned char *io_add_space_do_something( IOBuffer *io, int bytes, int force ) +  ATTRIBUTE((noclone,noinline)); +  static unsigned char *io_add_space_do_something( 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    * (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
pike.git/src/modules/_Stdio/buffer.cmod:254:       * And this one:       || (io_len(io)+bytes < io->allocated    && io->len+bytes >= io->allocated)       */       if( LIKELY(!io->locked_move) )    { -  if( io->len == io->offset ) -  io->offset = io->len = 0; -  else if( UNLIKELY((force && io->offset) || (io->offset > io->len>>1)) ) +  if( UNLIKELY((force && io->offset) || (io->offset > io->len>>1)) )    {    memmove( io->buffer, io_read_pointer(io), io_len(io) );    io->num_move++;    io->len -= io->offset;    io->offset = 0;    }    }       if( UNLIKELY(io->len + bytes > io->allocated) )    {
pike.git/src/modules/_Stdio/buffer.cmod:280:    new_len = ((new_len+32)*2)-32;    while( new_len < io->len + bytes );       io->buffer = xrealloc( io->buffer, new_len );    io->num_malloc++;    io->allocated = new_len;    }    return io->buffer+io->len;    }    +  static unsigned char *io_add_space( IOBuffer *io, int bytes, int force ) +  { +  if( io->len == io->offset ) +  io->offset = io->len = 0; +  if( !force && io->malloced && !io->locked && io->len+bytes < io->allocated ) +  return io->buffer+io->len; +  return io_add_space_do_something( io, bytes, force ); +  }       /*! @decl protected bool range_error( int howmuch )    *!    *! This function is called when an attempt is made to read out of bounds.    *!    *! The default implementation simply returns @expr{0@} (zero).    *!    *! Override this function to change the behavior.    *!    *! @param howmuch
pike.git/src/modules/_Stdio/buffer.cmod:504:       if( (total/(size_t)each) < (size_t)len )    {    if( io_range_error( io, len+io->len-io->offset ) )    return io_avail_mul(io,len,each);    return 0;    }    return 1;    }    -  static size_t io_append( IOBuffer *io, void *p, int bytes ) +  static size_t io_append( IOBuffer *io, const void *p, int bytes )    {    memcpy( io_add_space( io, bytes, 0 ), p, bytes );    io->len += bytes;    io_trigger_output( io );    return io_len(io);    }       static size_t io_read( IOBuffer *io, void *to, size_t len )    {    if( !io_avail(io,len))
pike.git/src/modules/_Stdio/buffer.cmod:596:    /* ensure only 0:s */    for( i=0; i<extra; i++ )    {    if( io_read_byte_uc(io) )    Pike_error("Integer (%dbit) overflow.\n", SIZEOF_INT_TYPE*8);    }    len=SIZEOF_INT_TYPE;    }    if( len == SIZEOF_INT_TYPE )    { -  res = io_read_byte_uc(io); -  if( res > 127 ) +  if( *io_read_pointer(io) > 127 )    Pike_error("Signed (%dbit) overflow.\n", SIZEOF_INT_TYPE*8); -  len--; +     } -  else -  res = 0; +     return io_read_number_uc( io, len );    }       static struct object *io_read_bignum( IOBuffer *io, size_t len )    {    int i;    struct pike_string *num;    LONGEST res;    num = io_read_string( io, len );    if( !num ) return NULL;
pike.git/src/modules/_Stdio/buffer.cmod:624:    push_int( 256 );    return clone_object( get_auto_bignum_program(), 2 );    }       static void io_add_bignum( IOBuffer *io, struct object *o, int width )    {    char *p;    INT_TYPE len;       push_int(256); -  apply( o, "digits", 1 ) - ; +  apply( o, "digits", 1 );       p = Pike_sp[-1].u.string->str;    len = Pike_sp[-1].u.string->len;       if( len > width )    Pike_error("Number too large to store in %d bits\n", width*8);       if( len < width )    {    INT_TYPE null = 0;
pike.git/src/modules/_Stdio/buffer.cmod:647:    {    int a = MIN(width-len, (int)sizeof(INT_TYPE));    io_append( io, &null, a );    width-=a;    }    }    io_append( io, p, width );    pop_stack();    }    -  static void io_add_int_uc( IOBuffer *io, INT_TYPE i, size_t bytes ) +  static void io_add_int_uc( IOBuffer *io, ptrdiff_t i, size_t bytes )    {    unsigned char *x = io->buffer+io->len;    io->len += bytes;    while(bytes--)    {    x[bytes] = i;    i>>=8;    }    }    -  static size_t io_add_int( IOBuffer *io, INT_TYPE i, size_t bytes ) +  static size_t io_add_int( IOBuffer *io, ptrdiff_t i, size_t bytes )    {    unsigned char *x = io_add_space(io, bytes, 0);    io_add_int_uc( io, i, bytes );    io_trigger_output( io );    return io_len( io );    }       static size_t io_rewind( IOBuffer *io, INT_TYPE n )    {    if( n < 0 || (io->offset < (unsigned)n) )
pike.git/src/modules/_Stdio/buffer.cmod:701:       static void io_append_int_uc( IOBuffer *io, unsigned INT32 i )    {    *((INT32 *)(io->buffer+io->len)) = htonl(i);    io->len+=4;    }          static size_t io_svalue_len( IOBuffer *UNUSED(io), struct svalue *p )    { -  union { -  struct string_builder *b; -  struct sysmem *s; -  IOBuffer *io; -  } src; -  +     if( TYPEOF(*p) == PIKE_T_STRING )    { -  if( p->u.string->size_shift ) -  Pike_error("Only string(0..255) supported\n"); +  if( !p->u.string->size_shift )    return p->u.string->len;    } -  +     if( TYPEOF(*p) == PIKE_T_OBJECT )    { -  struct object *x = p->u.object; -  -  if( (src.io = get_storage(x, IOBuffer_program)) ) -  return io_len(src.io); -  -  if( (src.b = string_buffer( x )) ) -  { -  if( src.b->s->size_shift ) -  Pike_error("Only string(0..255) supported\n"); -  else -  return src.b->s->len; +  size_t len; +  if( get_memory_object_memory( p->u.object, NULL, &len, NULL ) ) +  return len;    } -  -  if( (src.s = system_memory( x )) ) -  return src.s->size; +  Pike_error("Illegal argument (not an 8bit string or 8bit buffer object)\n");    } -  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( LIKELY(TYPEOF(*s) == PIKE_T_INT) )    return s->u.integer;   
pike.git/src/modules/_Stdio/buffer.cmod:755:    {    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");    }       static void io_append_svalue( IOBuffer *io, struct svalue *p ) +  ATTRIBUTE((noinline)); +  +  static void io_append_svalue( IOBuffer *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("IOBuffer only handles 8bit data\n");    if( !io->buffer )    {
pike.git/src/modules/_Stdio/buffer.cmod:794:    Pike_error("Attempt to append a cyclic array to a buffer.\n");       for(i=0; i<argp->size; i++ )    io_append_svalue( io, argp->item+i );       END_CYCLIC();    }    break;    case PIKE_T_OBJECT:    { -  struct object *x = p->u.object; -  union { -  IOBuffer *io; -  struct string_builder *b; +  size_t len; +  void *ptr;    struct sysmem *s; -  } src; +  enum memobj_type t = get_memory_object_memory( p->u.object, &ptr, &len, NULL );    -  if( (src.io = get_storage(x, IOBuffer_program)) ) +  if( !io->buffer && t==MEMOBJ_SYSTEM_MEMORY )    { -  io_append( io, io_read_pointer(src.io), io_len(src.io) ); -  /* io_consume( src.io, io_len(src.io) );*/ -  } -  else if( (src.b = string_buffer( x )) ) -  { -  if( src.b->s->size_shift ) -  Pike_error("Only string(0..255) supported\n"); -  io_append( io, src.b->s->str, src.b->s->len ); -  } -  else if( (src.s = system_memory( x )) ) -  { -  if( !io->buffer ) -  { -  io->source = x; -  io->buffer = src.s->p; -  io->len = src.s->size; +  io->buffer = ptr; +  io->len = len; +  +  io->source = p->u.object;    io->source->refs++; -  +  return;    } -  +  if( t != MEMOBJ_NONE ) +  io_append( io, ptr, len );    else -  io_append( io, src.s->p, src.s->size ); -  } -  else -  { -  default: +     Pike_error("Unsupported argument type\n");    } -  } +     break;    case PIKE_T_INT:    {    unsigned char a = p->u.integer;    io_append( io, &a, 1 );    }    }    }      #undef THIS
pike.git/src/modules/_Stdio/buffer.cmod:923:    /*! @decl int __fd_set_output( object f )    *!    *! 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( int(0..0)|object f )    {    IOBuffer *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;
pike.git/src/modules/_Stdio/buffer.cmod:1079:    pop_stack();    ref_push_object(io->this);    }       /*! @decl IOBuffer add_byte( int(0..255) )    *! @decl IOBuffer add_int8( int(0..255) )    *! Adds a single byte to the buffer.    */    PIKEFUN IOBuffer add_byte( int i )    { -  unsigned char a = i&255; -  io_append( THIS, &a, 1 ); +  IOBuffer *io = THIS; +  *io_add_space(io,1,0)=i; +  io->len++; +  Pike_sp--;    ref_push_object(Pike_fp->current_object);    }       PIKEFUN IOBuffer add_int8( int i )    { -  unsigned char a = i&255; -  io_append( THIS, &a, 1 ); +  IOBuffer *io = THIS; +  *io_add_space(io,1,0)=i; +  io->len++; +  Pike_sp--;    ref_push_object(Pike_fp->current_object);    }       /*! @decl IOBuffer add_int16( int(0..65535) )    *! @decl IOBuffer add_short( int(0..65535) )    *!    *! Add a 16-bit network byte order value to the buffer    */    PIKEFUN IOBuffer add_int16( int i )    { -  unsigned short a = htons((i&65535)); -  io_append( THIS, &a, 2 ); +  IOBuffer *io = THIS; +  unsigned char *p = io_add_space(io,2,0); +  p[0] = i>>8; +  p[1] = i; +  io->len += 2;    ref_push_object(Pike_fp->current_object);    }       PIKEFUN IOBuffer add_short( int i )    { -  unsigned short a = htons((i&65535)); -  io_append( THIS, &a, 2 ); +  IOBuffer *io = THIS; +  unsigned char *p = io_add_space(io,2,0); +  p[0] = i>>8; +  p[1] = i; +  io->len += 2;    ref_push_object(Pike_fp->current_object);    }       /*! @decl IOBuffer add_int32( int i )    *! Adds a 32 bit network byte order value to the buffer    */    PIKEFUN int(0..) add_int32( int i )    { -  INT32 a = htonl(i); -  io_append( THIS, &a, 4 ); +  IOBuffer *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;    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 of data followed by @[data] to the buffer.
pike.git/src/modules/_Stdio/buffer.cmod:1175:    }       /*! @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 ) +  PIKEFUN IOBuffer add_int( object|int i, int width )    { -  io_add_int( THIS, i, width ); +  pop_stack(); /* width */ +  if( TYPEOF(*i) == PIKE_T_INT ) +  { +  io_add_int( THIS, i->u.integer, width );    Pike_sp--; -  ref_push_object(Pike_fp->current_object); +     } -  -  PIKEFUN IOBuffer add_int( object o, int width ) +  else    { -  pop_stack(); /* width */ +     convert_stack_top_to_bignum(); -  io_add_bignum( THIS, Pike_sp[-1].u.object, width ); +  io_add_bignum( THIS, i->u.object, width );    pop_stack(); /* o. */ -  +  }    ref_push_object(Pike_fp->current_object);    }       /*! @decl IOBuffer add_ints( array(int) integers, int(0..255) len )    *!    *! Add the integers in the specified array, @[len] bytes per int.    *! Equivalent to calling @[add_int] for each integer, but faster,    *! and if an error occurs the buffer will contain no new    *! data. Either all or none of the integers will be added.    *!
pike.git/src/modules/_Stdio/buffer.cmod:2019:    *! so the buffer creation is fast regardless of the length of the    *! string.    *!    *! However, as an example, if the buffer is created with a 100Gb    *! @[System.Memory] mmap:ed file as the @[contents] and you later on    *! try to modify the buffer using one of the @[add] functions (or    *! @[sprintf] and similar) the old contents @b{will@} be copied.    *!    *! You can use @[read_only()] to avoid accidents.    */ -  PIKEFUN void create( string|object x ) +  PIKEFUN void create( int|void|string|object|array x )    flags ID_PROTECTED;    { -  io_append_svalue( THIS, Pike_sp-1 ); -  } -  -  PIKEFUN void create( int len ) -  flags ID_PROTECTED; -  { +     IOBuffer *this = THIS;    if( this->buffer )    Pike_error("Can not initialize twice.\n"); -  if( len <= 0 ) +  if( args == 0 ) +  { +  this->buffer = xalloc(256-32); +  this->allocated = 256-32; +  this->malloced = 1; +  } +  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 = MAX(len,1);    this->malloced = 1;    } -  -  PIKEFUN void create( ) -  flags ID_PROTECTED; -  { -  IOBuffer *this = THIS; -  if( this->buffer ) -  Pike_error("Can not initialize twice.\n"); -  this->buffer = xalloc(256-32); -  this->allocated = 256-32; -  this->malloced = 1; +  else +  io_append_svalue( THIS, x );    }      /*! @endclass    */       INIT {    IOBuffer *this = THIS;    memset( this, 0, sizeof(IOBuffer));    this->this = Pike_fp->current_object;    }
pike.git/src/modules/_Stdio/buffer.cmod:2084:    INIT    start_new_program();    low_inherit(generic_error_program,0,0,0,0,0);    add_integer_constant( "buffer_error", 1, 0 );    buffer_error_program = end_program();   }         void exit_stdio_buffer(void)   { -  if( shm_program ) free_program( shm_program ); -  if( sbuf_program ) free_program( sbuf_program ); +     free_program( buffer_error_program );    EXIT   }   /*! @endmodule    */