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

version» Context lines:

pike.git/src/modules/_Stdio/buffer.cmod:2129:    *!    *! Make the buffer permanently read only.    *! @note    *! You can use lock() to do this temporarily.    */    PIKEFUN void read_only()    {    io_lock( THIS );    }    +  +  static struct object* io_create_rewind_key( IOBuffer *io ); +  +  /*! @decl UnwindKey rewind_on_error() +  *! +  *! 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 or otherwise let the +  *! object fall out of scope. +  *! +  *! Take some care with these objects, if you create multiple ones +  *! at once the results might be somewhat confusing if you do not +  *! release them in the reverse order they were created in (then +  *! again, you almost certainly really only need one) +  *! +  *! Use @[destruct] or @[UnwindKey.release] to stop the buffer from being rewound. +  *! +  *! You can call @[update] in the generated object to change where +  *! it will be rewound to. +  *! +  *! The typical usecase of this object is when pasing a packet +  *! protocol with variable length packets where the lenght is not +  *! immediately known. It saves you from keeping track of how much +  *! to rewind if you had not actually gotten the whole packet yet. +  *! +  *! @example +  *! @code +  *! void parse_packet( Stdio.IOBuffer b ) +  *! { +  *! Stdio.IOBuffer.UnwindKey rewind = b->rewind_on_error(); +  *! b->set_error_mode(1); +  *! +  *! switch( b->read_int8() ) // packet type +  *! { +  *! case DATA: +  *! int channel = b->read_int8(); +  *! Stdio.IOBuffer data = b->read_hbuffer( 4 ); +  *! // we have read the whole packet, so no longer rewind on error. +  *! rewind->release(); +  *! return handle_data_packet( chennel, data ); +  *! } +  *! } +  *! @endcode +  */ +  PIKEFUN object rewind_on_error() +  { +  push_object( io_create_rewind_key( 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    *! size, or if no argument is given, 226 bytes.    *!    *! If @[contents] are specified a new buffer with the contents of    *! the given string/System.Memory or String.Buffer will be created.    *!
pike.git/src/modules/_Stdio/buffer.cmod:2183:    this->buffer = xalloc(1);    else    this->buffer = xalloc(len);    this->allocated = MAX(len,1);    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;    }       EXIT {    IOBuffer *this = THIS;    io_unlink_external_storage( this );    if( this->output )    free_object(this->output);    if( this->error_mode )    free_program( this->error_mode );    if( this->malloced )    free( this->buffer );    free(this->stash.ptr);    } -  +  +  + /*! @class UnwindKey +  *! +  *! The return value of unwind_when_released() +  *! +  *! This object will cause the buffer to unwind to the position it +  *! was at when the object was created when it is released +  *! (when it falls out of scope, explicit destruct does not count). +  */ +  +  PIKECLASS UnwindKey +  flags PROGRAM_DESTRUCT_IMMEDIATE; +  { +  CVAR IOBuffer *io; +  CVAR struct object *obj; +  CVAR size_t rewind_to; +  +  /*! @decl void release() +  *! Do not rewind if the object is released. +  *! +  *! This is equivalent to calling destruct() on the object. +  */ +  PIKEFUN void release() +  { +  destruct_object(Pike_fp->current_object, DESTRUCT_EXPLICIT);    }    -  +  /*! @decl void update() +  *! +  *! Update the location the buffer will be rewound to to the current +  *! position of the buffer. +  */ +  PIKEFUN void update() +  { +  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 ) +  flags ID_PRIVATE; +  { +  if( reason > 1 ) /* no refs or gc */ +  { +  if( THIS->io && THIS->obj->prog ) +  THIS->io->offset = THIS->rewind_to; +  } +  } +  +  PIKEFUN void create() +  flags ID_PRIVATE; +  { +  THIS->obj = 0; +  THIS->io = 0; +  Pike_error("Not supported\n"); +  } +  } + } +  +  +  + static struct object* io_create_rewind_key( IOBuffer *io ) + { +  struct object *o = fast_clone_object( IOBuffer_UnwindKey_program ); +  struct IOBuffer_UnwindKey_struct *s = (void*)o->storage; +  add_ref(io->this); +  s->obj = io->this; +  s->rewind_to = io->offset; +  s->io = io; +  io->locked_move++; +  return o; + } +  + /*! @endclass +  * UnwindKey +  */ +  + /*! @endclass +  * IOBuffer +  */ +  +  + /*! @endmodule +  * Stdio +  */ +  +    void init_stdio_buffer(void)   {    INIT    start_new_program();    low_inherit(generic_error_program,0,0,0,0,0);    add_integer_constant( "buffer_error", 1, 0 );    buffer_error_program = end_program();   }         void exit_stdio_buffer(void)   {    free_program( buffer_error_program );    EXIT   } - /*! @endmodule -  */ +