8cccac2014-08-28Per Hedbor #include "global.h"
540b6c2014-09-01Per Hedbor #include "fdlib.h" #include "pike_netlib.h"
8cccac2014-08-28Per Hedbor #include "object.h" #include "interpret.h" #include "operators.h" #include "bignum.h" #include "sscanf.h" #include "builtin_functions.h"
540b6c2014-09-01Per Hedbor #include "interpret.h"
3ecc992014-09-08Henrik Grubbström (Grubba) #include "cyclic.h"
540b6c2014-09-01Per Hedbor #include "backend.h" #include "fd_control.h" #include "file_machine.h" #include "file.h"
8cccac2014-08-28Per Hedbor #include "whitespace.h" #include "pike_types.h"
540b6c2014-09-01Per Hedbor #include "pike_threadlib.h"
8cccac2014-08-28Per Hedbor #include "iobuffer.h"
8f08202014-08-28Per Hedbor #include "module_support.h"
8cccac2014-08-28Per Hedbor #include <arpa/inet.h> #define DEFAULT_CMOD_STORAGE static DECLARATIONS
fbc3bf2014-09-08Per Hedbor struct sysmem { unsigned char *p; size_t size; };
8b141e2014-09-01Per Hedbor  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 );
fbc3bf2014-09-08Per Hedbor }
8b141e2014-09-01Per Hedbor  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 );
fbc3bf2014-09-08Per Hedbor }
8b141e2014-09-01Per Hedbor 
fbc3bf2014-09-08Per Hedbor static struct program *buffer_error_program;
8b141e2014-09-01Per Hedbor 
540b6c2014-09-01Per Hedbor /*! @module Stdio */
8cccac2014-08-28Per Hedbor /*! @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 *! the beginning and adding to the end, and will try to minimize the *! amount of data copying that is done. *!
8b141e2014-09-01Per Hedbor  *! The class maintains two separate offsets, one for reading and one *! for writing. The functions that add data all do so at the write *! offset (the end of the buffer), and reading is done from the read *! offset (the start of the buffer). *! *! The class can also be used to directly read from and write to *! filedescriptors if so desired. This eliminates at least one memory *! copy. *! *! @note *! The "avoid copy" part means that a IOBuffer will never shrink *! unless you call the @[trim] function. *!
8cccac2014-08-28Per Hedbor  */ PIKECLASS IOBuffer { CVAR IOBuffer b;
50c7192014-09-10Per Hedbor #if PRECOMPILE_API_VERSION > 5 PIKEVAR int b.num_malloc; PIKEVAR int b.num_move; #endif
9629ad2014-09-01Per Hedbor  static void io_set_error_mode( IOBuffer *io, struct program *m )
8cccac2014-08-28Per Hedbor  {
fbc3bf2014-09-08Per Hedbor  if( m ) m->refs++; if( io->error_mode ) free_program( io->error_mode ); io->error_mode = m;
8cccac2014-08-28Per Hedbor  } static size_t io_len( IOBuffer *io ) { return io->len-io->offset; } static void io_unlock( IOBuffer *io ) { io->locked--; } static void io_lock( IOBuffer *io ) { io->locked++; } static void io_ensure_unlocked(IOBuffer *io) { if( io->locked ) Pike_error("Can not modify the buffer right now, " " there are active subbuffers.\n"); } 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; }
8f08202014-08-28Per Hedbor  static int io_is_whitespace( IOBuffer *io, size_t pos ) {
fbc3bf2014-09-08Per Hedbor  if( pos > io_len( io ) ) return -1; switch( io->buffer[io->offset+pos] ) { SPACECASE8 return 1; } return 0;
8f08202014-08-28Per Hedbor  }
50c7192014-09-10Per Hedbor  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; }
277b4e2014-09-08Per Hedbor  static int io_unstash_malloc( IOBuffer *io )
8cccac2014-08-28Per Hedbor  {
277b4e2014-09-08Per Hedbor  if( LIKELY(!io->stash.ptr) ) return 0;
fbc3bf2014-09-08Per Hedbor  if( io->stash.len >= io_len( io ) ) {
277b4e2014-09-08Per Hedbor  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) ); }
fbc3bf2014-09-08Per Hedbor  io->buffer = io->stash.ptr;
50c7192014-09-10Per Hedbor  io->malloced = 1;
fbc3bf2014-09-08Per Hedbor  io->len = io_len(io); io->offset = 0; io->allocated = io->stash.len;
50c7192014-09-10Per Hedbor  io_unlink_external_storage(io);
fbc3bf2014-09-08Per Hedbor  } else free( io->stash.ptr ); io->stash.ptr = 0; io->stash.len = 0;
277b4e2014-09-08Per Hedbor  return io->malloced;
fbc3bf2014-09-08Per Hedbor  } static void io_stash_malloc( IOBuffer *io ) { if( io->malloced ) { io->stash.ptr = io->buffer; io->stash.len = io->allocated; io->malloced = 0; io->buffer = 0; io->offset = 0; } } static void io_ensure_malloced( IOBuffer *io, int bytes ) { if( UNLIKELY(!io->malloced) )
8cccac2014-08-28Per Hedbor  { /* convert to malloced buffer from a shared one. */
277b4e2014-09-08Per Hedbor  if( !io_unstash_malloc(io) ) {
50c7192014-09-10Per Hedbor  unsigned char *old = io->buffer;
277b4e2014-09-08Per Hedbor  io->buffer = xalloc( io->len + bytes + 100 );
50c7192014-09-10Per Hedbor  io->malloced = 1;
277b4e2014-09-08Per Hedbor  io->allocated = io->len + bytes + 100; io->num_malloc++; memcpy( io->buffer, old, io->len );
50c7192014-09-10Per Hedbor  io_unlink_external_storage(io);
8cccac2014-08-28Per Hedbor  } }
fbc3bf2014-09-08Per Hedbor  }
8cccac2014-08-28Per Hedbor 
fbc3bf2014-09-08Per Hedbor  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 * (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. * * However, if we are not going to add any more data it makes * sense to not move. * * But, since the buffer is intended to be used mainly for * bufering of files, it is very likely we will add more. * * In much the same way it might make sense to move the data if * wthe data can be added without reallocation in that way, even if * less than 50% of the buffer is wasted. * * However, that might lead to O(n) performance. * * So, for now this check is disabled: if( io->len + bytes < io->allocated )
317fc32014-09-02Per Hedbor  return io->buffer+io->len;
fbc3bf2014-09-08Per Hedbor  * And this one: || (io_len(io)+bytes < io->allocated && io->len+bytes >= io->allocated) */ if( LIKELY(!io->locked_move) )
8cccac2014-08-28Per Hedbor  {
fbc3bf2014-09-08Per Hedbor  if( io->len == io->offset ) io->offset = io->len = 0;
277b4e2014-09-08Per Hedbor  else if( UNLIKELY((force && io->offset) || (io->offset > io->len>>1)) )
fbc3bf2014-09-08Per Hedbor  { memmove( io->buffer, io_read_pointer(io), io_len(io) ); io->num_move++; io->len -= io->offset; io->offset = 0; }
8cccac2014-08-28Per Hedbor  }
317fc32014-09-02Per Hedbor 
fbc3bf2014-09-08Per Hedbor  if( UNLIKELY(io->len + bytes > io->allocated) )
8cccac2014-08-28Per Hedbor  { size_t new_len = io->allocated;
fbc3bf2014-09-08Per Hedbor 
8cccac2014-08-28Per Hedbor  do new_len = ((new_len+32)*2)-32; while( new_len < io->len + bytes );
fbc3bf2014-09-08Per Hedbor 
8cccac2014-08-28Per Hedbor  io->buffer = xrealloc( io->buffer, new_len );
fbc3bf2014-09-08Per Hedbor  io->num_malloc++;
8cccac2014-08-28Per Hedbor  io->allocated = new_len; } return io->buffer+io->len; }
317fc32014-09-02Per Hedbor  /*! @decl protected bool range_error( int howmuch ) *! *! This function is called when an attempt is made to read out of bounds. *!
6b6e7d2014-09-07Henrik Grubbström (Grubba)  *! The default implementation simply returns @expr{0@} (zero).
317fc32014-09-02Per Hedbor  *!
6b6e7d2014-09-07Henrik Grubbström (Grubba)  *! Override this function to change the behavior. *! *! @param howmuch
317fc32014-09-02Per Hedbor  *! The argument @[howmuch] indicates how much data is needed: *!
6b6e7d2014-09-07Henrik Grubbström (Grubba)  *! @int *! @value 1.. *! Need @[howmuch] bytes more
611a8e2014-09-08Per Hedbor  *! @value 0
6b6e7d2014-09-07Henrik Grubbström (Grubba)  *! The amount of data needed is not certain. *! This most often happens when @[sscanf] or @[read_json] is used *! @value ..-1 *! Tried to @[unread] -@[howmuch] bytes. There is usually no way to satisfy *! the requested range.
317fc32014-09-02Per Hedbor  *!
6b6e7d2014-09-07Henrik Grubbström (Grubba)  *! The only supported way is to extract the data from the buffer, *! add the requested amount of "go backbuffer", add the data *! back, and forward -@[howmuch] bytes. *! @endint
317fc32014-09-02Per Hedbor  *! *! @returns *! *! @[true] if the operation should be retried, @[false] otherwise. *! *! Do not return true unless you have added data to the buffer, *! doing so could result in an infinite loop (since no data is *! added, the range_error will be called again immediately). */ PIKEFUN int(0..1) range_error( int howmuch ) flags ID_PROTECTED;
8cccac2014-08-28Per Hedbor  {
317fc32014-09-02Per Hedbor  /* Default: throw error if so desired, otherwise return 0. */ pop_n_elems(args); push_int(0); } static void io_range_error_throw( IOBuffer *io, int howmuch )
fbc3bf2014-09-08Per Hedbor  ATTRIBUTE((noclone,noinline)); static void io_range_error_throw( IOBuffer *io, int howmuch )
317fc32014-09-02Per Hedbor  { if( io->error_mode ) {
6b6e7d2014-09-07Henrik Grubbström (Grubba)  if( howmuch > 0 )
317fc32014-09-02Per Hedbor  {
6b6e7d2014-09-07Henrik Grubbström (Grubba)  push_text("Trying to read %d bytes outside allowed range\n");
317fc32014-09-02Per Hedbor  push_int(howmuch); f_sprintf(2); } else push_text("Illegal arguments\n"); ref_push_object( io->this ); push_object(clone_object(io->error_mode, 2)); f_throw(1); } }
fbc3bf2014-09-08Per Hedbor  static struct pike_string *io_read_string( IOBuffer *io, size_t len ) ATTRIBUTE((noclone,noinline));
8923ca2014-09-03Per Hedbor  static size_t io_rewind( IOBuffer *io, INT_TYPE n );
fbc3bf2014-09-08Per Hedbor  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( IOBuffer *io, ONERROR *x ) { struct rewind_to *rew = xalloc( sizeof( struct rewind_to ) ); #if defined(PIKE_DEBUG) 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 ) { #if defined(PIKE_DEBUG)
50c7192014-09-10Per Hedbor  struct rewind_to *rew = x->arg;
c000962014-09-08Henrik Grubbström (Grubba)  if( io->locked_move != rew->old_locked_move )
fbc3bf2014-09-08Per Hedbor  Pike_fatal( "Invalid io_rewind_on_error nesting\n");
c000962014-09-08Henrik Grubbström (Grubba)  free( rew );
50c7192014-09-10Per Hedbor #endif UNSET_ONERROR( (*x) ); io->locked_move--;
fbc3bf2014-09-08Per Hedbor  } 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 ); }
277b4e2014-09-08Per Hedbor  static void io_unset_unwrite_on_error( IOBuffer *UNUSED(io), ONERROR *x )
fbc3bf2014-09-08Per Hedbor  { UNSET_ONERROR( (*x) ); free( x->arg ); }
5944b32014-09-11Henrik Grubbström (Grubba)  static ptrdiff_t io_call_write( IOBuffer *io, struct object *o, ptrdiff_t nbytes )
50c7192014-09-10Per Hedbor  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 ) { 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); }
5944b32014-09-11Henrik Grubbström (Grubba)  static ptrdiff_t io_call_write( IOBuffer *io, struct object *o, ptrdiff_t bytes )
50c7192014-09-10Per Hedbor  { if( bytes > 0 ) {
5944b32014-09-11Henrik Grubbström (Grubba)  ptrdiff_t l = 0;
50c7192014-09-10Per Hedbor  struct pike_string *s = io_read_string( io,bytes ); if( s ) { io->output_triggered = 1; push_string( s ); apply( o, "write", 1 ); l = Pike_sp[-1].u.integer; pop_stack(); if( l < 0 ) { io_rewind( io, bytes ); return -1; } if( bytes > (unsigned)l ) io_rewind( io, bytes-l ); } return l; } return -1; }
8923ca2014-09-03Per Hedbor  static void io_trigger_output( IOBuffer *io ) {
50c7192014-09-10Per Hedbor  if( io->output && !io->output_triggered ) { struct my_file *fd; if( (fd = get_storage( io->output, file_program )) )
8923ca2014-09-03Per Hedbor  {
50c7192014-09-10Per Hedbor  io_set_events( io, fd, PIKE_BIT_FD_WRITE_OOB, PIKE_FD_WRITE ); io->output_triggered = 1;
8923ca2014-09-03Per Hedbor  }
50c7192014-09-10Per Hedbor  else io_call_write( io, io->output, MINIMUM( io_len(io), 100 ) ); }
8923ca2014-09-03Per Hedbor  }
5944b32014-09-11Henrik Grubbström (Grubba)  static int io_range_error( IOBuffer *io, ptrdiff_t howmuch )
fbc3bf2014-09-08Per Hedbor  ATTRIBUTE((noclone,noinline));
5944b32014-09-11Henrik Grubbström (Grubba)  static int io_range_error( IOBuffer *io, ptrdiff_t howmuch )
317fc32014-09-02Per Hedbor  { int res; struct svalue *osp = Pike_sp;
fbc3bf2014-09-08Per Hedbor  push_int64( howmuch );
7fec642014-09-02Henrik Grubbström (Grubba)  apply_current( f_IOBuffer_range_error_fun_num, 1 );
317fc32014-09-02Per Hedbor  res = Pike_sp[-1].u.integer; pop_n_elems( Pike_sp-osp ); if( !res ) io_range_error_throw( io, howmuch ); return res;
8cccac2014-08-28Per Hedbor  }
5944b32014-09-11Henrik Grubbström (Grubba)  static int io_avail( IOBuffer *io, ptrdiff_t len )
8cccac2014-08-28Per Hedbor  { if( len < 0 || len + io->offset > io->len ) {
317fc32014-09-02Per Hedbor  if( len < 0 ) io_range_error_throw( io, 0 ); else if( io_range_error( io, len+io->len-io->offset ) ) return io_avail(io,len); return 0;
8cccac2014-08-28Per Hedbor  } return 1; }
5944b32014-09-11Henrik Grubbström (Grubba)  static int io_avail_mul( IOBuffer *io, ptrdiff_t len, ptrdiff_t each )
fbc3bf2014-09-08Per Hedbor  { /* safely check if len*each is available. */ size_t total = io_len(io); if( len < 0 || each <= 0 ) { io_range_error_throw( io, 0 ); return 0; } 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; }
8cccac2014-08-28Per Hedbor  static size_t io_append( IOBuffer *io, void *p, int bytes ) { memcpy( io_add_space( io, bytes, 0 ), p, bytes ); io->len += bytes;
8923ca2014-09-03Per Hedbor  io_trigger_output( io );
8cccac2014-08-28Per Hedbor  return io_len(io); } static size_t io_read( IOBuffer *io, void *to, size_t len ) { if( !io_avail(io,len)) return 0; memcpy( to, io_read_pointer(io), len ); io_consume( io, len ); return len; } static struct pike_string *io_read_string( IOBuffer *io, size_t len ) { struct pike_string *s; if( len > 0x7fffffff ) Pike_error("This region is too large to convert to a string.\n");
fbc3bf2014-09-08Per Hedbor  if( !io_avail(io,len)) return NULL;
8cccac2014-08-28Per Hedbor  s = begin_shared_string( len );
317fc32014-09-02Per Hedbor  io_read( io, s->str, len );
8cccac2014-08-28Per Hedbor  return end_shared_string(s); } static struct object *io_read_buffer( IOBuffer *io, size_t len, int do_copy ) { struct object *b; IOBuffer *to; if( !io_avail(io,len)) return NULL; b = low_clone( IOBuffer_program ); to = get_storage(b,IOBuffer_program); io_lock( io ); to->buffer = io_read_pointer(io); to->len = len; to->sub = Pike_fp->current_object; to->sub->refs++; io_consume( io, len ); if( do_copy )
fbc3bf2014-09-08Per Hedbor  io_ensure_malloced( to, 0 );
8cccac2014-08-28Per Hedbor  return b; } static int io_read_byte_uc( IOBuffer *io ) { return io->buffer[io->offset++]; }
fbc3bf2014-09-08Per Hedbor  static INT_TYPE io_read_number_uc( IOBuffer *io, size_t len )
8cccac2014-08-28Per Hedbor  {
fbc3bf2014-09-08Per Hedbor  size_t i; LONGEST res = 0; for( i=0; i<len; i++ ) { res <<= 8; res |= io_read_byte_uc(io); } return res;
8cccac2014-08-28Per Hedbor  } static LONGEST io_read_number( IOBuffer *io, size_t len ) { size_t i; LONGEST res; if( !io_avail(io, len) ) return -1; if( len > SIZEOF_INT_TYPE ) { unsigned int extra = len-SIZEOF_INT_TYPE; /* 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 ) Pike_error("Signed (%dbit) overflow.\n", SIZEOF_INT_TYPE*8); len--; } else res = 0;
fbc3bf2014-09-08Per Hedbor  return io_read_number_uc( io, len );
8cccac2014-08-28Per Hedbor  } 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; push_string( num ); push_int( 256 ); return clone_object( get_auto_bignum_program(), 2 ); }
fbc3bf2014-09-08Per Hedbor  static void io_add_bignum( IOBuffer *io, struct object *o, int width )
8cccac2014-08-28Per Hedbor  {
fbc3bf2014-09-08Per Hedbor  char *p; INT_TYPE len; push_int(256); 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; while( len < width ) {
9e39622014-09-08Henrik Grubbström (Grubba)  int a = MIN(width-len, (int)sizeof(INT_TYPE));
fbc3bf2014-09-08Per Hedbor  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 ) {
73599d2014-09-08Per Hedbor  unsigned char *x = io->buffer+io->len;
8cccac2014-08-28Per Hedbor  io->len += bytes; while(bytes--) {
8b65362014-09-11Stephen R. van den Berg  x[bytes] = i;
8cccac2014-08-28Per Hedbor  i>>=8; }
fbc3bf2014-09-08Per Hedbor  } static size_t io_add_int( IOBuffer *io, INT_TYPE i, size_t bytes ) { unsigned char *x = io_add_space(io, bytes, 0); io_add_int_uc( io, i, bytes );
8923ca2014-09-03Per Hedbor  io_trigger_output( io );
8cccac2014-08-28Per Hedbor  return io_len( io ); } static size_t io_rewind( IOBuffer *io, INT_TYPE n ) { if( n < 0 || (io->offset < (unsigned)n) ) {
317fc32014-09-02Per Hedbor  if( n < 0 ) io_range_error_throw( io, 0 ); else if( io_range_error(io,-(long)(n-io->offset)) ) return io_rewind( io, n );
8cccac2014-08-28Per Hedbor  return -1; } io->offset -= n;
8923ca2014-09-03Per Hedbor  io_trigger_output( io );
8cccac2014-08-28Per Hedbor  return io->offset; }
342f562014-09-02Per Hedbor  static void io_append_byte_uc( IOBuffer *io, unsigned char byte ) { io->buffer[io->len++] = byte; } static void io_append_short_uc( IOBuffer *io, unsigned short shrt ) { *((short *)(io->buffer+io->len)) = htons(shrt); io->len+=2; } static void io_append_int_uc( IOBuffer *io, unsigned INT32 i ) { *((INT32 *)(io->buffer+io->len)) = htonl(i); io->len+=4; }
fbc3bf2014-09-08Per Hedbor  static size_t io_svalue_len( IOBuffer *UNUSED(io), struct svalue *p ) {
50c7192014-09-10Per Hedbor  union { struct string_builder *b; struct sysmem *s; IOBuffer *io; } src;
fbc3bf2014-09-08Per Hedbor 
50c7192014-09-10Per Hedbor  if( TYPEOF(*p) == PIKE_T_STRING ) { if( p->u.string->size_shift ) Pike_error("Only string(0..255) supported\n"); return p->u.string->len; }
fbc3bf2014-09-08Per Hedbor 
50c7192014-09-10Per Hedbor  if( TYPEOF(*p) == PIKE_T_OBJECT ) { struct object *x = p->u.object;
fbc3bf2014-09-08Per Hedbor 
50c7192014-09-10Per Hedbor  if( (src.io = get_storage(x, IOBuffer_program)) ) return io_len(src.io);
fbc3bf2014-09-08Per Hedbor 
50c7192014-09-10Per Hedbor  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;
fbc3bf2014-09-08Per Hedbor  }
50c7192014-09-10Per Hedbor  if( (src.s = system_memory( x )) ) return src.s->size; } Pike_error("Illegal argument (not a string or buffer object)\n");
fbc3bf2014-09-08Per Hedbor  } /* NOTE: Can return negative integers. */
342f562014-09-02Per Hedbor  static INT_TYPE get_small_int( struct svalue *s )
50c7192014-09-10Per Hedbor  ATTRIBUTE((noclone,noinline)); static INT_TYPE get_small_int( struct svalue *s )
342f562014-09-02Per Hedbor  {
50c7192014-09-10Per Hedbor  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");
342f562014-09-02Per Hedbor  }
fbc3bf2014-09-08Per Hedbor  static void io_append_svalue( IOBuffer *io, struct svalue *p ) { switch( TYPEOF(*p) ) { case PIKE_T_STRING: { struct pike_string *s = p->u.string;
973a692014-09-10Henrik Grubbström (Grubba)  if( !s->len ) return;
fbc3bf2014-09-08Per Hedbor  if( s->size_shift ) Pike_error("IOBuffer only handles 8bit data\n"); if( !io->buffer ) {
973a692014-09-10Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG if (io->str) Pike_fatal("IOBuffer with string but NULL buffer.\n"); #endif
fbc3bf2014-09-08Per Hedbor  io->str = s; io->buffer = (unsigned char*)s->str; io->len = s->len; s->refs++; } else io_append( io, s->str, s->len ); } break; case PIKE_T_ARRAY: { struct array *argp = p->u.array; INT_TYPE i;
3ecc992014-09-08Henrik Grubbström (Grubba)  DECLARE_CYCLIC(); if (BEGIN_CYCLIC(io, argp)) Pike_error("Attempt to append a cyclic array to a buffer.\n");
fbc3bf2014-09-08Per Hedbor  for(i=0; i<argp->size; i++ ) io_append_svalue( io, argp->item+i );
3ecc992014-09-08Henrik Grubbström (Grubba)  END_CYCLIC();
fbc3bf2014-09-08Per Hedbor  } break; case PIKE_T_OBJECT: { struct object *x = p->u.object; union { IOBuffer *io; struct string_builder *b; struct sysmem *s; } src; if( (src.io = get_storage(x, IOBuffer_program)) ) { io_append( io, io_read_pointer(src.io), io_len(src.io) );
277b4e2014-09-08Per Hedbor  /* io_consume( src.io, io_len(src.io) );*/
fbc3bf2014-09-08Per Hedbor  } 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->source->refs++; } 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 ); } } }
342f562014-09-02Per Hedbor 
fbc3bf2014-09-08Per Hedbor #undef THIS #define THIS (&(((struct IOBuffer_struct *)Pike_fp->current_storage)->b))
342f562014-09-02Per Hedbor 
8cccac2014-08-28Per Hedbor  /* pike functions */
559c922014-09-03Per Hedbor  /*! @decl int(0..) input_from( Stdio.Stream f, int|void nbytes )
8b141e2014-09-01Per Hedbor  *!
559c922014-09-03Per Hedbor  *! Read data from @[f] into this buffer. If @[nbytes] is not *! specified, read until there is no more data to read (currently).
317fc32014-09-02Per Hedbor  *! *! Returns the amount of data that was read *! *! @note *! Please note that this funcition will read all data from the *! filedescriptor unless it's set to be non-blocking.
8b141e2014-09-01Per Hedbor  */
432a822014-09-04Per Hedbor  PIKEFUN int(0..) input_from( object f, int|void _nbytes, int|void _once )
8b141e2014-09-01Per Hedbor  { IOBuffer *io = THIS; size_t sz = io_len( io );
559c922014-09-03Per Hedbor  size_t bread = 0, nbytes = (size_t)-1;
8b141e2014-09-01Per Hedbor  struct my_file *fd;
432a822014-09-04Per Hedbor  int once = 0;
8b141e2014-09-01Per Hedbor 
559c922014-09-03Per Hedbor  if( _nbytes ) nbytes = _nbytes->u.integer;
432a822014-09-04Per Hedbor  if( _once ) once = _once->u.integer;
8b141e2014-09-01Per Hedbor  if( (fd = get_storage( f, file_program )) ) { while( 1 ) { unsigned char *ptr = io_add_space( io, 4096, 0 ); int res;
559c922014-09-03Per Hedbor  res = fd_read( fd->box.fd, ptr, MINIMUM(4096,nbytes) );
8b141e2014-09-01Per Hedbor  if( res == -1 && errno == EINTR ) continue; if( res <= 0 ) break;
432a822014-09-04Per Hedbor 
559c922014-09-03Per Hedbor  nbytes -= res;
8b141e2014-09-01Per Hedbor  io->len += res; bread += res;
432a822014-09-04Per Hedbor  if( res != 4096 || once)
8b141e2014-09-01Per Hedbor  break; }
50c7192014-09-10Per Hedbor  io_set_events( io, fd, PIKE_BIT_FD_READ_OOB, PIKE_FD_READ );
8b141e2014-09-01Per Hedbor  } else {
559c922014-09-03Per Hedbor  /* some other object. Just call read */ while( nbytes )
8b141e2014-09-01Per Hedbor  {
559c922014-09-03Per Hedbor  push_int( MINIMUM(4096,nbytes) );
8b141e2014-09-01Per Hedbor  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"); io_append( io, Pike_sp[-1].u.string->str, Pike_sp[-1].u.string->len );
559c922014-09-03Per Hedbor  nbytes -= Pike_sp[-1].u.string->len;
8b141e2014-09-01Per Hedbor  pop_stack(); } } RETURN bread; }
8923ca2014-09-03Per Hedbor  /*! @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.
fbc3bf2014-09-08Per Hedbor  *!
8923ca2014-09-03Per Hedbor  *! If f is 0 the state is cleared. */
50c7192014-09-10Per Hedbor  PIKEFUN void __fd_set_output( int(0..0)|object f )
8923ca2014-09-03Per Hedbor  { IOBuffer *io = THIS; if( io->output ) free_object(io->output); io->output_triggered = 0;
50c7192014-09-10Per Hedbor  if( TYPEOF(*f) != PIKE_T_OBJECT ) io->output = 0; else { io->output = f->u.object; io->output->refs++; }
8923ca2014-09-03Per Hedbor  }
2062be2014-09-09Henrik Grubbström (Grubba)  /*! @decl int(-1..) output_to( Stdio.Stream f, int(0..)|void nbytes )
540b6c2014-09-01Per Hedbor  *! *! Write data from the buffer to the indicated file. *!
2062be2014-09-09Henrik Grubbström (Grubba)  *! @param nbytes
559c922014-09-03Per Hedbor  *! If @[nbytes] is not specified the whole buffer will be written *! if possible. Otherwise at most @[nbytes] will be written.
2062be2014-09-09Henrik Grubbström (Grubba)  *! *! @returns
b064882014-09-11Stephen R. van den Berg  *! Will return the number of bytes that have been written successfully.
2062be2014-09-09Henrik Grubbström (Grubba)  *!
b064882014-09-11Stephen R. van den Berg  *! If no bytes have been written successfully and @expr{f->write()@} failed *! with an error, @expr{-1@} will be returned.
540b6c2014-09-01Per Hedbor  */
2062be2014-09-09Henrik Grubbström (Grubba)  PIKEFUN int(-1..) output_to( object f, int|void _nbytes )
540b6c2014-09-01Per Hedbor  { IOBuffer *io = THIS;
5944b32014-09-11Henrik Grubbström (Grubba)  ptrdiff_t written = 0, nbytes = (ptrdiff_t)(((size_t)~0)>>1);
540b6c2014-09-01Per Hedbor  struct my_file *fd;
5944b32014-09-11Henrik Grubbström (Grubba)  ptrdiff_t sz = io_len( io );
97775b2014-09-11Henrik Grubbström (Grubba)  int write_fun_num; struct inherit *inh;
fbc3bf2014-09-08Per Hedbor 
559c922014-09-03Per Hedbor  if( !sz )
cd79ef2014-09-03Per Hedbor  {
50c7192014-09-10Per Hedbor  io_range_error(io, sz); sz = io_len(io);
cd79ef2014-09-03Per Hedbor  }
559c922014-09-03Per Hedbor  if( _nbytes )
50c7192014-09-10Per Hedbor  nbytes = _nbytes->u.integer;
559c922014-09-03Per Hedbor 
97775b2014-09-11Henrik Grubbström (Grubba)  if ((write_fun_num = find_identifier("write", f->prog)) == -1) { Pike_error("Cannot call unknown function \"write\".\n"); } inh = INHERIT_FROM_INT(f->prog, write_fun_num); if( inh->prog == file_program )
540b6c2014-09-01Per Hedbor  {
97775b2014-09-11Henrik Grubbström (Grubba)  fd = get_inherit_storage( f, inh - f->prog->inherits );
540b6c2014-09-01Per Hedbor  /* lock this object. */
559c922014-09-03Per Hedbor  while( sz > written && nbytes )
540b6c2014-09-01Per Hedbor  {
5944b32014-09-11Henrik Grubbström (Grubba)  ptrdiff_t rd = MINIMUM(MINIMUM(sz-written,4096),nbytes);
540b6c2014-09-01Per Hedbor  unsigned char *ptr = io_read_pointer( io );
5944b32014-09-11Henrik Grubbström (Grubba)  ptrdiff_t res;
540b6c2014-09-01Per Hedbor  res = fd_write( fd->box.fd, ptr, rd ); if( res == -1 && errno == EINTR ) continue;
2062be2014-09-09Henrik Grubbström (Grubba)  if( res <= 0 ) {
50c7192014-09-10Per Hedbor  fd->my_errno = errno; if (!written) written = -1;
540b6c2014-09-01Per Hedbor  break;
50c7192014-09-10Per Hedbor  }
540b6c2014-09-01Per Hedbor  io_consume( io, res ); written += res;
cd79ef2014-09-03Per Hedbor  nbytes-=res;
540b6c2014-09-01Per Hedbor  }
50c7192014-09-10Per Hedbor  io_set_events( io, fd, PIKE_BIT_FD_WRITE_OOB, PIKE_FD_WRITE);
540b6c2014-09-01Per Hedbor  } else { /* some other object. Just call write */
559c922014-09-03Per Hedbor  while( sz > written && nbytes)
540b6c2014-09-01Per Hedbor  {
559c922014-09-03Per Hedbor  size_t rd = MINIMUM(MINIMUM(sz-written,4096),nbytes);
5944b32014-09-11Henrik Grubbström (Grubba)  ptrdiff_t wr = io_call_write( io, f, rd );
50c7192014-09-10Per Hedbor  if( wr <= 0 ) {
540b6c2014-09-01Per Hedbor  io_rewind(io, rd );
50c7192014-09-10Per Hedbor  if (!written) written = -1;
540b6c2014-09-01Per Hedbor  break; }
50c7192014-09-10Per Hedbor  written += wr; if( wr < 4096 ) { io_rewind(io, rd-wr );
540b6c2014-09-01Per Hedbor  break; } } } RETURN written; }
9629ad2014-09-01Per Hedbor  PIKEFUN int(0..) _size_object( )
8cccac2014-08-28Per Hedbor  {
8b141e2014-09-01Per Hedbor  RETURN THIS->malloced ? THIS->allocated : 0;
8cccac2014-08-28Per Hedbor  }
fbc3bf2014-09-08Per Hedbor  /*! @decl IOBuffer add( AddArgument ... data ) *! @code *! private typedef @[System.Memory]|@[Stdio.IOBuffer]|@[String.Buffer] BufferObject; *! private typedef BufferObject|string(8bit)|int(8bit)|array(AddArgument) AddArgument; *! @endcode
8cccac2014-08-28Per Hedbor  *!
8b141e2014-09-01Per Hedbor  *! Add the items in data to the end of the buffer.
fbc3bf2014-09-08Per Hedbor  *! *! The supported argument types are: *!
d4c85e2014-09-08Henrik Grubbström (Grubba)  *! @mixed *! @type string(0..255) *! An eight bit string. *! @type int(0..255) *! A single byte *! @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(AddArgument) *! Add all elements in the array individually. Each element may be *! any one of the types listed here. *! @endmixed
8b141e2014-09-01Per Hedbor  *!
342f562014-09-02Per Hedbor  *! @seealso
8b141e2014-09-01Per Hedbor  *! @[sprintf], @[add_int8], @[add_int16], @[add_int32], @[add_int] *! and *! @[add_hstring]
8cccac2014-08-28Per Hedbor  */
fbc3bf2014-09-08Per Hedbor  PIKEFUN IOBuffer add( object|string|int|array(object|string|int) ... argp)
8cccac2014-08-28Per Hedbor  { int i; IOBuffer *io = THIS;
fbc3bf2014-09-08Per Hedbor  if( args == 1 && !io_len( io ) ) io_stash_malloc( io );
8cccac2014-08-28Per Hedbor  for(i=0; i<args; i++ )
fbc3bf2014-09-08Per Hedbor  io_append_svalue( io, argp+i );
8b141e2014-09-01Per Hedbor 
fbc3bf2014-09-08Per Hedbor  pop_stack();
317fc32014-09-02Per Hedbor  ref_push_object(io->this);
8cccac2014-08-28Per Hedbor  }
342f562014-09-02Per Hedbor  /*! @decl IOBuffer add_byte( int(0..255) ) *! @decl IOBuffer add_int8( int(0..255) )
8cccac2014-08-28Per Hedbor  *! Adds a single byte to the buffer. */
317fc32014-09-02Per Hedbor  PIKEFUN IOBuffer add_byte( int i )
8cccac2014-08-28Per Hedbor  { unsigned char a = i&255;
317fc32014-09-02Per Hedbor  io_append( THIS, &a, 1 ); ref_push_object(Pike_fp->current_object);
8cccac2014-08-28Per Hedbor  }
317fc32014-09-02Per Hedbor  PIKEFUN IOBuffer add_int8( int i )
8cccac2014-08-28Per Hedbor  { unsigned char a = i&255;
317fc32014-09-02Per Hedbor  io_append( THIS, &a, 1 ); ref_push_object(Pike_fp->current_object);
8cccac2014-08-28Per Hedbor  }
342f562014-09-02Per Hedbor  /*! @decl IOBuffer add_int16( int(0..65535) ) *! @decl IOBuffer add_short( int(0..65535) )
8cccac2014-08-28Per Hedbor  *! *! Add a 16-bit network byte order value to the buffer */
317fc32014-09-02Per Hedbor  PIKEFUN IOBuffer add_int16( int i )
8cccac2014-08-28Per Hedbor  { unsigned short a = htons((i&65535));
317fc32014-09-02Per Hedbor  io_append( THIS, &a, 2 ); ref_push_object(Pike_fp->current_object);
8cccac2014-08-28Per Hedbor  }
317fc32014-09-02Per Hedbor  PIKEFUN IOBuffer add_short( int i )
8cccac2014-08-28Per Hedbor  { unsigned short a = htons((i&65535));
317fc32014-09-02Per Hedbor  io_append( THIS, &a, 2 ); ref_push_object(Pike_fp->current_object);
8cccac2014-08-28Per Hedbor  }
342f562014-09-02Per Hedbor  /*! @decl IOBuffer add_int32( int i )
8cccac2014-08-28Per Hedbor  *! Adds a 32 bit network byte order value to the buffer */
9629ad2014-09-01Per Hedbor  PIKEFUN int(0..) add_int32( int i )
8cccac2014-08-28Per Hedbor  { INT32 a = htonl(i);
317fc32014-09-02Per Hedbor  io_append( THIS, &a, 4 ); ref_push_object(Pike_fp->current_object);
8cccac2014-08-28Per Hedbor  }
342f562014-09-02Per Hedbor  /*! @decl IOBuffer add_hstring( string(0..255) data, int size_size )
fbc3bf2014-09-08Per Hedbor  *! @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 )
50c7192014-09-10Per Hedbor  *! @decl IOBuffer add_hstring( array data, int size_size )
8cccac2014-08-28Per Hedbor  *!
50c7192014-09-10Per Hedbor  *! Adds length of data followed by @[data] to the buffer.
8cccac2014-08-28Per Hedbor  *!
50c7192014-09-10Per Hedbor  *! This is identical to *! @code{sprintf("%"+size_size+"H",(string)Stdio.IObuffer(data))@} but *! significantly faster.
8cccac2014-08-28Per Hedbor  *!
50c7192014-09-10Per Hedbor  *! @[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
8cccac2014-08-28Per Hedbor  */
fbc3bf2014-09-08Per Hedbor 
50c7192014-09-10Per Hedbor  PIKEFUN IOBuffer add_hstring( string|object|array str, int size_size )
fbc3bf2014-09-08Per Hedbor  { IOBuffer *io = THIS;
50c7192014-09-10Per Hedbor  size_t len = io_svalue_len(io, str);
fbc3bf2014-09-08Per Hedbor 
50c7192014-09-10Per Hedbor  if( size_size < (int)sizeof(size_t) &&
fbc3bf2014-09-08Per Hedbor  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 );
50c7192014-09-10Per Hedbor  io_append_svalue( io, str );
9fc2ef2014-09-08Per Hedbor  pop_n_elems(args);
fbc3bf2014-09-08Per Hedbor  ref_push_object(io->this); }
317fc32014-09-02Per Hedbor  /*! @decl IOBuffer add_int( int i, int(0..) width )
8cccac2014-08-28Per Hedbor  *! *! Adds a generic integer to the buffer as an (width*8)bit *! network byteorder number. *! *! @[width] must be less than Int.NATIVE_MAX. *! */
317fc32014-09-02Per Hedbor  PIKEFUN IOBuffer add_int( int i, int width )
8cccac2014-08-28Per Hedbor  {
317fc32014-09-02Per Hedbor  io_add_int( THIS, i, width );
fbc3bf2014-09-08Per Hedbor  Pike_sp--;
317fc32014-09-02Per Hedbor  ref_push_object(Pike_fp->current_object);
8cccac2014-08-28Per Hedbor  }
317fc32014-09-02Per Hedbor  PIKEFUN IOBuffer add_int( object o, int width )
8cccac2014-08-28Per Hedbor  {
fbc3bf2014-09-08Per Hedbor  pop_stack(); /* width */
8cccac2014-08-28Per Hedbor  convert_stack_top_to_bignum();
fbc3bf2014-09-08Per Hedbor  io_add_bignum( THIS, Pike_sp[-1].u.object, width ); pop_stack(); /* o. */
317fc32014-09-02Per Hedbor  ref_push_object(Pike_fp->current_object);
8cccac2014-08-28Per Hedbor  }
342f562014-09-02Per Hedbor  /*! @decl IOBuffer add_ints( array(int) integers, int(0..255) len ) *! *! Add the integers in the specified array, @[len] bytes per int.
fbc3bf2014-09-08Per Hedbor  *! 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. *! *! Errors can occur if one of the elements in @[integers] is not *! actually an integer, if sizeof(integers)*len is bigger than can *! be represented in a size_t, or if the buffer cannot grow due to *! an out of memory condition.
342f562014-09-02Per Hedbor  */ PIKEFUN IOBuffer add_ints( array(int) a, int bpi ) {
fbc3bf2014-09-08Per Hedbor  int i,l = a->size; struct svalue *it = a->item; unsigned char *ptr;
5944b32014-09-11Henrik Grubbström (Grubba)  ptrdiff_t n;
fbc3bf2014-09-08Per Hedbor  ONERROR e; IOBuffer *io = THIS;
342f562014-09-02Per Hedbor 
fbc3bf2014-09-08Per Hedbor  io_unwrite_on_error(io, &e);
342f562014-09-02Per Hedbor 
fbc3bf2014-09-08Per Hedbor  if( bpi < 0 ) Pike_error("Illegal int width\n"); #if SIZEOF_SIZE_T == 4 if( DO_INT32_MUL_OVERFLOW( l, bpi, &n ) ) #else
50c7192014-09-10Per Hedbor  if( DO_INT64_MUL_OVERFLOW( l, bpi, &n ) )
fbc3bf2014-09-08Per Hedbor #endif
5944b32014-09-11Henrik Grubbström (Grubba)  Pike_error("Result size exceeds ptrdiff_t size\n");
fbc3bf2014-09-08Per Hedbor  io_add_space( io, n, 0 ); switch( bpi ) {
50c7192014-09-10Per Hedbor  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++ ) io_append_short_uc( io, get_small_int(it+i) ); break; case 4: for( i=0; i<l; i++ ) io_append_int_uc( io, get_small_int(it+i) ); break; case 3:
342f562014-09-02Per Hedbor #if SIZEOF_INT_TYPE > 4
50c7192014-09-10Per Hedbor  case 5: case 6: case 7:
342f562014-09-02Per Hedbor #endif
50c7192014-09-10Per Hedbor  for( i=0; i<l; i++ )
fbc3bf2014-09-08Per Hedbor  io_add_int_uc( io, get_small_int(it+i), bpi ); break; default: /* bignums. */ for( i=0; i<l; i++ ) {
50c7192014-09-10Per Hedbor  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");
fbc3bf2014-09-08Per Hedbor  } } io_unset_unwrite_on_error( io, &e ); io_trigger_output( io );
50c7192014-09-10Per Hedbor  Pike_sp--; pop_stack();
fbc3bf2014-09-08Per Hedbor  ref_push_object(io->this);
342f562014-09-02Per Hedbor  }
8cccac2014-08-28Per Hedbor  /*! @decl protected int `[](int off) *! *! Return the character at the specified offset. */
9629ad2014-09-01Per Hedbor  PIKEFUN int(0..255) `[]( int off )
8cccac2014-08-28Per Hedbor  flags ID_PROTECTED; { IOBuffer *io = THIS; pop_stack(); if( off < 0 ) off = io_len(io)-off; if( io_avail( io, off ) ) push_int( io_read_pointer(io)[off] ); else push_int(-1); } /*! @decl protected int `[]=(int off, int char) *! *! Set the character at the specified offset to @[char]. */
9629ad2014-09-01Per Hedbor  PIKEFUN int(0..255) `[]=( int off, int val )
8cccac2014-08-28Per Hedbor  flags ID_PROTECTED; { IOBuffer *io = THIS;
fbc3bf2014-09-08Per Hedbor  io_ensure_malloced( io, 0 );
8cccac2014-08-28Per Hedbor  if( off < 0 ) off = io_len(io)-off; if( io_avail( io, off ) ) { io_read_pointer(io)[off]=(val&0xff); } else { /* hm, well. We could extend the buffer? */ push_int(-1); } } /*! @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. */
9629ad2014-09-01Per Hedbor  PIKEFUN int(0..) _sizeof()
8cccac2014-08-28Per Hedbor  flags ID_PROTECTED; { push_int64(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. */
9629ad2014-09-01Per Hedbor  PIKEFUN string(0..255) cast(string to)
8cccac2014-08-28Per Hedbor  { if( to != literal_string_string ) { push_undefined(); return; } if( io_len(THIS) > 0x7fffffff ) Pike_error("This buffer is too large to convert to a string.\n"); push_string(make_shared_binary_string((void*)io_read_pointer(THIS), (INT32)io_len(THIS))); }
fbc3bf2014-09-08Per Hedbor  /*! @decl IOBuffer set_error_mode(int m) *! @decl IOBuffer set_error_mode(program m)
8cccac2014-08-28Per Hedbor  *! *! Set the error mode of this buffer to @[m]. *!
9629ad2014-09-01Per Hedbor  *! If true operations that would normally return 0 (like trying to *! read too much) will instead throw an error. If @[m] is a program *! a clone of it will be thrown on error.
8cccac2014-08-28Per Hedbor  *! *! This is useful when parsing received data, you do not have to *! verify that each and every read operation suceeds. *! *! However, the non-error mode is more useful when checking to see *! if a packet/segment/whatever has arrived. *! *! The thrown error object will have the constant buffer_error set *! to a non-false value. *! *! @example *! @code *! void read_callback(int i, string new_data) *! { *! inbuffer->add( new_data ); *! *! while( IOBuffer packet = inbuffer->read_hbuffer(2) ) *! { *! packet->set_error_mode(Buffer.THROW_ERROR); *! if( mixed e = catch( handle_packet( packet ) ) ) *! if( e->buffer_error ) *! protocol_error(); // illegal data in packet *! else *! throw(e); // the other code did something bad *! } *! } *! *! *! void handle_packet( IOBuffer pack ) *! { *! switch( pack->read_int8() ) *! { *! ... *! case HEADER_FRAME: *! int num_headers = pack->read_int32(); *! for( int i = 0; i<num_headers; i++ ) *! headers[pack->read_hstring(2)] = pack->read_hstring(2); *! ... *! } *! } *! @endcode */
fbc3bf2014-09-08Per Hedbor  PIKEFUN IOBuffer set_error_mode( int|program m )
8cccac2014-08-28Per Hedbor  {
9629ad2014-09-01Per Hedbor  if( TYPEOF(*m) == PIKE_T_INT ) io_set_error_mode( THIS, m->u.integer ? buffer_error_program : 0 ); else { io_set_error_mode( THIS, program_from_svalue(m)); } pop_stack();
fbc3bf2014-09-08Per Hedbor  ref_push_object(Pike_fp->current_object);
8cccac2014-08-28Per Hedbor  } /*! @decl object lock() *! *! Makes this buffer read only until the returned object is released. *! *! @note *! This currently simply returns a 0-length subbuffer. */ PIKEFUN IOBuffer lock() { push_object( io_read_buffer( THIS, 0, 0 ) ); }
9629ad2014-09-01Per Hedbor  PIKEFUN string(0..255) _sprintf(int o, mapping ignore)
8cccac2014-08-28Per Hedbor  flags ID_PROTECTED; { pop_n_elems(args); if( o == 'O' ) {
317fc32014-09-02Per Hedbor  push_text("%O(%d bytes, read=[..%d] data=[%d..%d] free=[%d..%d] %s%s)"); ref_push_program(Pike_fp->current_object->prog);
8cccac2014-08-28Per Hedbor  /* io_len [..offset] [offset..len] [..allocated] */ push_int(io_len(THIS)); push_int(THIS->offset-1); push_int(THIS->offset);
317fc32014-09-02Per Hedbor 
8cccac2014-08-28Per Hedbor  push_int(THIS->len-1); push_int(THIS->len); push_int(THIS->allocated);
8b141e2014-09-01Per Hedbor  push_text( (THIS->str ? "string" : THIS->malloced ? "allocated" : "subbuffer" ) );
8cccac2014-08-28Per Hedbor  if( THIS->locked ) push_text(" (read only)"); else push_text("");
317fc32014-09-02Per Hedbor  f_sprintf(10);
8cccac2014-08-28Per Hedbor  } else push_undefined(); } /*! @decl string(8bit) read_hstring( int(0..) n ) *! *! Identical in functionality to @[read](@[read_number](@[n])) but *! faster. *! *! Read a network byte order number of size n*8 bits, then return the *! indicated number of bytes as a string. *! *! If there is not enough data available return 0. *! *! Note that pike string can not be longer than 0x7fffffff bytes (~2Gb). */
9629ad2014-09-01Per Hedbor  PIKEFUN string(0..255) read_hstring( int bytes )
8cccac2014-08-28Per Hedbor  { LONGEST len;
fbc3bf2014-09-08Per Hedbor  IOBuffer *io = THIS;
8cccac2014-08-28Per Hedbor  struct pike_string *s;
fbc3bf2014-09-08Per Hedbor  ONERROR e;
8cccac2014-08-28Per Hedbor 
fbc3bf2014-09-08Per Hedbor  io_rewind_on_error( io, &e ); len = io_read_number( io, bytes );
ebd0042014-09-05Henrik Grubbström (Grubba)  if (len < 0) { /* io_avail() in io_read_number() failed. */
fbc3bf2014-09-08Per Hedbor  CALL_AND_UNSET_ONERROR(e);
ebd0042014-09-05Henrik Grubbström (Grubba)  push_int(0); return; } /* NB: We assume that io_avail() in io_read_string() doesn't throw. */
fbc3bf2014-09-08Per Hedbor  s = io_read_string( io, len );
ebd0042014-09-05Henrik Grubbström (Grubba)  if( s ) {
fbc3bf2014-09-08Per Hedbor  io_unset_rewind_on_error( io, &e );
8cccac2014-08-28Per Hedbor  push_string(s);
ebd0042014-09-05Henrik Grubbström (Grubba)  } else {
fbc3bf2014-09-08Per Hedbor  CALL_AND_UNSET_ONERROR(e);
8cccac2014-08-28Per Hedbor  push_int(0);
ebd0042014-09-05Henrik Grubbström (Grubba)  }
8cccac2014-08-28Per Hedbor  } /*! @decl IOBuffer read_hbuffer( int n ) *! @decl IOBuffer read_hbuffer( int n, bool copy ) *! *! Same as @[read_hstring], but returns the result as an IOBuffer. *! *! No data is copied unless @[copy] is specified and true, the new *! buffer points into the old one. *! *! @note *! As long as the subbuffer exists no data can be added to the *! main buffer. *! *! Usually this is OK, since it often represents something that *! should be parsed before the next whatever is extracted from *! the buffer, but do take care. *! *! If you need to unlink the new buffer after it has been *! created, call @[trim] in it. */
9629ad2014-09-01Per Hedbor  PIKEFUN IOBuffer read_hbuffer( int bytes, int|void copy )
8cccac2014-08-28Per Hedbor  {
ebd0042014-09-05Henrik Grubbström (Grubba)  LONGEST len;
8cccac2014-08-28Per Hedbor  int do_copy = 0;
fbc3bf2014-09-08Per Hedbor  IOBuffer *io = THIS; ONERROR e; io_rewind_on_error( io, &e );
ebd0042014-09-05Henrik Grubbström (Grubba) 
8cccac2014-08-28Per Hedbor  if( copy ) do_copy = copy->u.integer; pop_n_elems(args);
fbc3bf2014-09-08Per Hedbor  len = io_read_number( io, bytes ); if( len >= 0 && io_avail( io, len ) ) { push_object( io_read_buffer( io, len, do_copy ) ); io_unset_rewind_on_error( io, &e );
ebd0042014-09-05Henrik Grubbström (Grubba)  return; }
fbc3bf2014-09-08Per Hedbor  CALL_AND_UNSET_ONERROR(e); push_int(0); return; /* io_read_buffer will not throw here, since io_avail is true. */
8cccac2014-08-28Per Hedbor  } /*! @decl IOBuffer read_buffer( int n ) *! @decl IOBuffer read_buffer( int n, bool copy ) *! *! Same as @[read], but returns the result as an IOBuffer. *! *! No data is copied unless @[copy] is specified and true, the new buffer *! points into the old one. *! *! @note *! As long as the subbuffer exists no data can be added to the main buffer. *! *! Usually this is OK, since it often represents something that *! should be parsed before the next whatever is extracted from *! the buffer, but do take care. */ PIKEFUN IOBuffer read_buffer( int bytes, int|void copy ) { int do_copy = 0; struct object *o; if( copy ) do_copy = copy->u.integer; pop_n_elems(args); if( (o = io_read_buffer( THIS, bytes, do_copy )) ) push_object(o); else push_int(0); }
fbc3bf2014-09-08Per Hedbor  /*! @decl IOBuffer sprintf(strict_sprintf_format format, sprintf_args ... args)
8cccac2014-08-28Per Hedbor  *! *! Appends the output from @[sprintf] at the end of the buffer. *! *! This is somewhat faster than add(sprintf(...)) since no *! intermediate string is created. */
9629ad2014-09-01Per Hedbor  PIKEFUN int(0..) sprintf(mixed ... ignored)
8cccac2014-08-28Per Hedbor  rawtype tFuncV(tAttr("strict_sprintf_format", tOr(tStr, tObj)), tAttr("sprintf_args", tMix), tStr); { ONERROR _e; struct string_builder tmp; INT_TYPE sz; init_string_builder(&tmp,0); SET_ONERROR(_e, free_string_builder, &tmp); low_f_sprintf(args, 0, &tmp ); if( tmp.s->size_shift ) Pike_error("IOBuffer only handles 8bit data\n"); sz = io_append( THIS, tmp.s->str, tmp.s->len ); pop_n_elems(args); CALL_AND_UNSET_ONERROR(_e);
fbc3bf2014-09-08Per Hedbor  ref_push_object(Pike_fp->current_object);
8cccac2014-08-28Per Hedbor  } /*! @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. *! *! The non-matching data will be left in the buffer. *! *! See @[array_sscanf] for more information. */ PIKEFUN array sscanf( string format ) { INT32 i; ptrdiff_t num_used; struct svalue *start = Pike_sp;
317fc32014-09-02Per Hedbor  retry:
8cccac2014-08-28Per Hedbor  i = low_sscanf_pcharp( MKPCHARP(io_read_pointer(THIS), 0), io_len(THIS), MKPCHARP(format->str,format->size_shift), format->len, &num_used, 0); if( !num_used ) {
317fc32014-09-02Per Hedbor  if( io_range_error(THIS,0) ) goto retry;
8cccac2014-08-28Per Hedbor  pop_n_elems(Pike_sp-start); push_int(0); } else { io_consume( THIS, num_used ); f_aggregate(Pike_sp-start); } }
8f08202014-08-28Per Hedbor  /*! @decl mixed read_json(int|void require_whitespace_separator) *! *! Read a single JSON expression from the buffer and return it.
317fc32014-09-02Per Hedbor  *!
8f08202014-08-28Per Hedbor  *! If @[require_whitespace_separator] is true there must be a whitespace *! after each json value (as an example, newline or space). *! *! The JSON is assumed to be utf-8 encoded. *! *! @returns *! UNDEFINED if no data is available to read. *! The read value otherwise. *! *! @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; static ptrdiff_t(*parse_json_pcharp)(PCHARP,size_t,int,char**); char *err = NULL; if( require_whitespace ) whites = require_whitespace->u.integer; if( !parse_json_pcharp ) parse_json_pcharp = PIKE_MODULE_IMPORT(Standards.JSON, parse_json_pcharp );
317fc32014-09-02Per Hedbor  retry:
8f08202014-08-28Per Hedbor  stop = parse_json_pcharp( MKPCHARP(io_read_pointer(THIS),0), io_len(THIS), 1|8, &err ); /* json_utf8 */ if( stop < 0 ) { if( -stop == (ptrdiff_t)io_len(THIS) || (err && !strncmp(err,"Unterminated",12))) {
317fc32014-09-02Per Hedbor  if( io_range_error(THIS,0) ) goto retry;
8f08202014-08-28Per Hedbor  push_undefined(); } else { /* FIXME: Use real json error? */ if( 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 ); } } else { if( whites && (io_is_whitespace(THIS,stop)<=0 && io_is_whitespace(THIS,stop-1)<=0)) { if( stop == (ptrdiff_t)io_len(THIS) ) {
317fc32014-09-02Per Hedbor  if( io_range_error(THIS,0) ) goto retry;
8f08202014-08-28Per Hedbor  pop_stack(); push_undefined(); } else 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 ); } } }
8cccac2014-08-28Per Hedbor  /*! @decl mixed match(string(8bit) format) *! *! Reads data from the beginning of the buffer to match the *! specifed format, then return the match. *! *! The non-matching data will be left in the buffer. *! *! This function is very similar to @[sscanf], but the *! result is the sum of the matches. Most useful to match *! a single value. *! *! @example *! @code *! // get the next whitespace separated word from the buffer. *! buffer->match("%*[ \t\r\n]%*[^ \t\r\n]"); *! @endcode */
9629ad2014-09-01Per Hedbor  PIKEFUN string(0..255)|int|float|array match( string format )
8cccac2014-08-28Per Hedbor  { INT32 i; ptrdiff_t num_used; struct svalue *start = Pike_sp;
317fc32014-09-02Per Hedbor  retry:
8cccac2014-08-28Per Hedbor  i = low_sscanf_pcharp( MKPCHARP(io_read_pointer(THIS), 0), io_len(THIS), MKPCHARP(format->str,format->size_shift), format->len,
fbc3bf2014-09-08Per Hedbor  &num_used,
8cccac2014-08-28Per Hedbor  0); if( !num_used ) {
317fc32014-09-02Per Hedbor  if( io_range_error(THIS,0) ) goto retry;
8cccac2014-08-28Per Hedbor  pop_n_elems(Pike_sp-start); push_int(0); } else { io_consume( THIS, num_used ); if( Pike_sp-start > 1 ) f_add(Pike_sp-start); } } /*! @decl void clear() *! *! Clear the buffer. */ PIKEFUN void clear( ) { IOBuffer *io = THIS; io->offset = io->len = 0; } /*! @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 *! This function could possibly throw an out-of-memory error *! if the realloc fails to find a new (smaller) memory area. */ PIKEFUN void trim( ) { IOBuffer *io = THIS; io_add_space( io, 0, 1 ); if( io->allocated > io->len+32 ) { io->buffer = xrealloc( io->buffer, io->len );
fbc3bf2014-09-08Per Hedbor  io->num_malloc++;
8cccac2014-08-28Per Hedbor  io->allocated = io->len; } } /*! @decl int(0..)|int(-1..-1) consume( int(0..) n ) *! *! Discard the first @[n] bytes from the buffer
fbc3bf2014-09-08Per Hedbor  *! *! Returns -1 on error and the amount of space still left otherwise.
8cccac2014-08-28Per Hedbor  */ PIKEFUN int(-1..) consume( int n ) { if( !io_avail( THIS, n ) ) push_int(-1); else push_int64( io_consume( THIS, n ) ); } /*! @decl int(0..)|int(-1..-1) unread( int(0..) n ) *! *! Rewind the buffer @[n] bytes. *! *! @returns *! *! This function returns how many more bytes of buffer is *! available to rewind, or -1 on error. *! *! @note *! *! Unless you add new data to the buffer using any of the add *! functions you can always rewind. *!
b064882014-09-11Stephen R. van den Berg  *! You can call @[unread(0)] to see how much.
8cccac2014-08-28Per Hedbor  */
9629ad2014-09-01Per Hedbor  PIKEFUN int(-1..) unread( int bytes )
8cccac2014-08-28Per Hedbor  { push_int64( io_rewind( THIS, bytes ) ); } /*! @decl string(8bit) read( int n ) *! *! Read @[bytes] bytes of data from the buffer. *! *! If there is not enough data available this returns 0. */
9629ad2014-09-01Per Hedbor  PIKEFUN string(0..255) read( int bytes )
8cccac2014-08-28Per Hedbor  {
317fc32014-09-02Per Hedbor  struct pike_string *s; s = io_read_string(THIS, bytes );
8cccac2014-08-28Per Hedbor  if( s )
317fc32014-09-02Per Hedbor  RETURN s; push_undefined();
8cccac2014-08-28Per Hedbor  } /*! @decl string(8bit) read( ) *! *! Read all data from the buffer. *! *! If there is not enough data available this returns 0. *! *! This is basically equivalent to (string)buffer, but it also *! removes the data from the buffer. */ PIKEFUN string(0..255) read() { struct pike_string * s = io_read_string(THIS, io_len(THIS));
317fc32014-09-02Per Hedbor  if( s ) RETURN s; push_undefined();
8cccac2014-08-28Per Hedbor  }
c5e3e52014-09-10Per Hedbor  /*! @decl int(8bit) read_int8() */ PIKEFUN int(8bit) read_int8( ) { IOBuffer *io = THIS; if( LIKELY(io_avail( io, 1 )) ) push_int( io_read_byte_uc(io) ); else push_int(-1); } /*! @decl int(16bit) read_int16() */ PIKEFUN int(0..65535) read_int16( ) { IOBuffer *io = THIS; if( LIKELY(io_avail( io, 2 )) ) push_int( io_read_number_uc(io,2) ); else push_int(-1); } /*! @decl int(24bit) read_int24() */ PIKEFUN int(0..16777215) read_int24( ) { IOBuffer *io = THIS; if( LIKELY(io_avail( io, 3 )) ) push_int( io_read_number_uc(io,3) ); else push_int(-1); }
0455182014-09-11Arne Goedeke  /*! @decl int(32bit) read_int32()
c5e3e52014-09-10Per Hedbor  */
0455182014-09-11Arne Goedeke  PIKEFUN int(0..4294967295) read_int32( )
c5e3e52014-09-10Per Hedbor  { #if SIZEOF_INT_TYPE > 4 IOBuffer *io = THIS; if( LIKELY(io_avail( io, 4 )) ) push_int( io_read_number_uc(io,4) ); else push_int(-1); #else push_int( io_read_number( 4 ) ); #endif }
74e52c2014-08-28Per Hedbor  /*! @decl int read_int( int n )
8cccac2014-08-28Per Hedbor  *!
fbc3bf2014-09-08Per Hedbor  *! Read a network byte order unsigned number of size n*8 bits, then
8cccac2014-08-28Per Hedbor  *! return it. *! *! Will return -1 if there is not enough buffer space available *! unless error mode is set to throw errors. */
9629ad2014-09-01Per Hedbor  PIKEFUN int(0..) read_int( int len )
8cccac2014-08-28Per Hedbor  { IOBuffer *io = THIS; struct object *o; pop_stack(); if( len < SIZEOF_INT_TYPE-1 ) /* will for sure fit. */ { push_int( io_read_number( io, len ) ); return; } if( (o = io_read_bignum(io, len )) ) { push_object(o); reduce_stack_top_bignum(); return; } push_int(-1); }
fbc3bf2014-09-08Per Hedbor  /*! @decl array(int) read_ints( int n, int width ) *! *! Read a list of @[n] network byte order unsigned numbers each of *! size @[width]*8 bits, then return it. *! *! Will return 0 if there is not enough buffer space available *! unless error mode is set to throw errors. */ PIKEFUN array(int(0..)) read_ints( int num, int len ) { IOBuffer *io = THIS; INT_TYPE i; struct object *o; struct array *a; pop_n_elems(2); if( !io_avail_mul( io, num, len ) ) { push_int(0); return; } 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 )); reduce_stack_top_bignum(); } f_aggregate(num); }
6d47962014-09-01Per Hedbor /*! @decl string _encode() *! @decl void _decode(string x) *! *! Encode and decode Stdio.IOBuffer objects. *! Only the buffer data is kept, no other state is saved. */ PIKEFUN string _encode() {
fbc3bf2014-09-08Per Hedbor  push_string(io_read_string(THIS, io_len(THIS)));
6d47962014-09-01Per Hedbor  } PIKEFUN void _decode(string(0..255) x) { IOBuffer *this = THIS; if( this->buffer ) Pike_error("Can not initialize twice.\n"); if( x->size_shift ) Pike_error("Can not handle non-8bit data.\n"); this->buffer = (unsigned char*)x->str; this->len = x->len; this->malloced = 0; this->str = x; x->refs++; }
8b141e2014-09-01Per Hedbor  /*! @decl void read_only()
8cccac2014-08-28Per Hedbor  *!
8b141e2014-09-01Per Hedbor  *! Make the buffer permanently read only. *! @note *! You can use lock() to do this temporarily. */ PIKEFUN void read_only() { io_lock( THIS ); } /*! @decl void create( int|void len ) *! @decl void create( string(8bit) contents ) *! @decl void create( System.Memory|String.Buffer contents ) *! *! If passed an integer or no argument, create a buffer of that
317fc32014-09-02Per Hedbor  *! size, or if no argument is given, 226 bytes.
8b141e2014-09-01Per Hedbor  *! *! If @[contents] are specified a new buffer with the contents of *! the given string/System.Memory or String.Buffer will be created.
8cccac2014-08-28Per Hedbor  *! *! @note
8b141e2014-09-01Per Hedbor  *! In the @[String.Buffer] case the data has to be copied unless *! there is only one reference to the String.Buffer object, since *! modifications of the String.Buffer would cause the IOBuffer to *! point into invalid memory. *! *! In all other cases this will not copy the string data, instead *! data will be read from the source until it needs to be modified, *! so the buffer creation is fast regardless of the length of the
8cccac2014-08-28Per Hedbor  *! string.
8b141e2014-09-01Per Hedbor  *! *! 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.
8cccac2014-08-28Per Hedbor  */
fbc3bf2014-09-08Per Hedbor  PIKEFUN void create( string|object x )
8cccac2014-08-28Per Hedbor  flags ID_PROTECTED; {
fbc3bf2014-09-08Per Hedbor  io_append_svalue( THIS, Pike_sp-1 );
8b141e2014-09-01Per Hedbor  }
8cccac2014-08-28Per Hedbor  PIKEFUN void create( int len ) flags ID_PROTECTED; { IOBuffer *this = THIS; if( this->buffer ) Pike_error("Can not initialize twice.\n");
fbc3bf2014-09-08Per Hedbor  if( len <= 0 ) this->buffer = xalloc(1); else this->buffer = xalloc(len); this->allocated = MAX(len,1);
8cccac2014-08-28Per Hedbor  this->malloced = 1; } PIKEFUN void create( ) flags ID_PROTECTED; { IOBuffer *this = THIS; if( this->buffer ) Pike_error("Can not initialize twice.\n");
317fc32014-09-02Per Hedbor  this->buffer = xalloc(256-32); this->allocated = 256-32;
8cccac2014-08-28Per Hedbor  this->malloced = 1; }
74e52c2014-08-28Per Hedbor /*! @endclass */
8cccac2014-08-28Per Hedbor  INIT { IOBuffer *this = THIS; memset( this, 0, sizeof(IOBuffer));
317fc32014-09-02Per Hedbor  this->this = Pike_fp->current_object;
8cccac2014-08-28Per Hedbor  } EXIT { IOBuffer *this = THIS;
50c7192014-09-10Per Hedbor  io_unlink_external_storage( this );
8923ca2014-09-03Per Hedbor  if( this->output ) free_object(this->output);
9629ad2014-09-01Per Hedbor  if( this->error_mode ) free_program( this->error_mode );
8cccac2014-08-28Per Hedbor  if( this->malloced ) free( this->buffer );
50c7192014-09-10Per Hedbor  free(this->stash.ptr);
8cccac2014-08-28Per Hedbor  } }
10150d2014-09-01Per Hedbor 
8cccac2014-08-28Per Hedbor void init_stdio_buffer(void) { INIT
10150d2014-09-01Per Hedbor  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();
8cccac2014-08-28Per Hedbor } void exit_stdio_buffer(void) {
8b141e2014-09-01Per Hedbor  if( shm_program ) free_program( shm_program ); if( sbuf_program ) free_program( sbuf_program );
10150d2014-09-01Per Hedbor  free_program( buffer_error_program );
8cccac2014-08-28Per Hedbor  EXIT }
540b6c2014-09-01Per Hedbor /*! @endmodule */