92ba30 | 2014-10-02 | Martin Nilsson | | /* -*- c -*-
|| This file is part of Pike. For copyright information see COPYRIGHT.
|| Pike is distributed under GPL, LGPL and MPL. See the file COPYING
|| for more information.
*/
|
8cccac | 2014-08-28 | Per Hedbor | | #include "global.h"
|
540b6c | 2014-09-01 | Per Hedbor | | #include "fdlib.h"
#include "pike_netlib.h"
|
8cccac | 2014-08-28 | Per Hedbor | | #include "object.h"
#include "interpret.h"
#include "operators.h"
#include "bignum.h"
#include "sscanf.h"
#include "builtin_functions.h"
|
540b6c | 2014-09-01 | Per Hedbor | | #include "interpret.h"
|
3ecc99 | 2014-09-08 | Henrik Grubbström (Grubba) | | #include "cyclic.h"
|
540b6c | 2014-09-01 | Per Hedbor | | #include "backend.h"
#include "fd_control.h"
#include "file_machine.h"
#include "file.h"
|
8cccac | 2014-08-28 | Per Hedbor | | #include "whitespace.h"
#include "pike_types.h"
|
540b6c | 2014-09-01 | Per Hedbor | | #include "pike_threadlib.h"
|
9d3bdd | 2014-10-01 | Martin Nilsson | | #include "buffer.h"
|
8f0820 | 2014-08-28 | Per Hedbor | | #include "module_support.h"
|
bf77d9 | 2015-05-16 | Arne Goedeke | | #include "bitvector.h"
|
8f0820 | 2014-08-28 | Per Hedbor | |
|
881ba1 | 2014-12-06 | Bill Welliver | | #ifdef HAVE_ARPA_INET_H
|
8cccac | 2014-08-28 | Per Hedbor | | #include <arpa/inet.h>
|
881ba1 | 2014-12-06 | Bill Welliver | | #endif
|
ae81d2 | 2014-09-18 | Per Hedbor | | #undef MP_INT
#include <gmp.h>
|
8cccac | 2014-08-28 | Per Hedbor | |
|
e3a7da | 2018-05-17 | Stephen R. van den Berg | | #define READ_CHUNKSIZE 32768
#define WRITE_CHUNKSIZE 32768
|
49c1b7 | 2018-05-17 | Stephen R. van den Berg | |
|
8cccac | 2014-08-28 | Per Hedbor | | #define DEFAULT_CMOD_STORAGE static
DECLARATIONS
|
fbc3bf | 2014-09-08 | Per Hedbor | | struct sysmem {
unsigned char *p;
size_t size;
};
|
8b141e | 2014-09-01 | Per Hedbor | |
|
fbc3bf | 2014-09-08 | Per Hedbor | | static struct program *buffer_error_program;
|
8b141e | 2014-09-01 | Per Hedbor | |
|
540b6c | 2014-09-01 | Per Hedbor | | /*! @module Stdio
*/
|
586df3 | 2016-12-30 | Henrik Grubbström (Grubba) | | /* Remap to not clash with String.Buffer. */
#define PROG_BUFFER_ID PROG_STDIO_BUFFER_ID
#define tObjImpl_BUFFER tObjImpl_STDIO_BUFFER
#define tObjIs_BUFFER tObjIs_STDIO_BUFFER
|
cb6501 | 2014-10-01 | Martin Nilsson | | /*! @class Buffer
|
8cccac | 2014-08-28 | Per Hedbor | | *!
*! 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.
*!
|
8b141e | 2014-09-01 | Per 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
|
cb6501 | 2014-10-01 | Martin Nilsson | | *! The "avoid copy" part means that a Buffer will never shrink
|
8b141e | 2014-09-01 | Per Hedbor | | *! unless you call the @[trim] function.
*!
|
8cccac | 2014-08-28 | Per Hedbor | | */
|
cb6501 | 2014-10-01 | Martin Nilsson | | PIKECLASS Buffer
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
f32cf9 | 2014-10-20 | Per Hedbor | | #ifdef PRECOMPILE_SUB_PIKEVARS
|
50c719 | 2014-09-10 | Per Hedbor | | PIKEVAR int b.num_malloc;
PIKEVAR int b.num_move;
|
f32cf9 | 2014-10-20 | Per Hedbor | | #else
#warning Stdio.Buffer should be compiled with a newer precompiler
#warning for full functionality. You can achieve this by touching
#warning src/modules/_Stdio/buffer.cmod and recompiling once the
#warning compilation is done.
|
50c719 | 2014-09-10 | Per Hedbor | | #endif
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | EXTRA
{
|
f32cf9 | 2014-10-20 | Per Hedbor | | PIKE_MAP_VARIABLE("__output", OFFSETOF(Buffer_struct,b.output),
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | tMix, PIKE_T_MIXED, ID_PRIVATE|ID_HIDDEN|ID_PROTECTED);
}
|
f32cf9 | 2014-10-20 | Per Hedbor | | CVAR Buffer b;
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | |
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_set_error_mode( Buffer *io, struct program *m )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
929b28 | 2014-09-18 | Henrik Grubbström (Grubba) | | if( m ) add_ref(m);
|
fbc3bf | 2014-09-08 | Per Hedbor | | if( io->error_mode ) free_program( io->error_mode );
io->error_mode = m;
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | static size_t io_len( Buffer *io )
|
8cccac | 2014-08-28 | Per Hedbor | | {
return io->len-io->offset;
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_unlock( Buffer *io )
|
8cccac | 2014-08-28 | Per Hedbor | | {
io->locked--;
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_lock( Buffer *io )
|
8cccac | 2014-08-28 | Per Hedbor | | {
io->locked++;
}
|
f3ed29 | 2014-09-11 | Per Hedbor | | static void io_was_locked( )
ATTRIBUTE((noclone,noinline));
static void io_was_locked( )
|
8cccac | 2014-08-28 | Per Hedbor | | {
Pike_error("Can not modify the buffer right now, "
" there are active subbuffers.\n");
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_ensure_unlocked(Buffer *io)
|
f3ed29 | 2014-09-11 | Per Hedbor | | {
if( io->locked )
io_was_locked( );
}
|
2c4241 | 2015-07-13 | Per Hedbor | | static void io_trim( Buffer *io )
ATTRIBUTE((noinline));
|
9db222 | 2017-07-30 | Arne Goedeke | | static void io_trim_waste( Buffer *io )
{
if( UNLIKELY(io->allocated > (io_len(io) * (1.0+io->max_waste))) )
io_trim(io);
}
|
5ca7e2 | 2017-06-29 | Arne Goedeke | | static INT_TYPE io_consume( Buffer *io, ptrdiff_t num )
|
8cccac | 2014-08-28 | Per Hedbor | | {
io->offset += num;
return io_len(io);
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static unsigned char *io_read_pointer(Buffer *io)
|
8cccac | 2014-08-28 | Per Hedbor | | {
return io->buffer + io->offset;
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static int io_is_whitespace( Buffer *io, size_t pos )
|
8f0820 | 2014-08-28 | Per Hedbor | | {
|
fbc3bf | 2014-09-08 | Per Hedbor | | if( pos > io_len( io ) )
return -1;
switch( io->buffer[io->offset+pos] )
{
SPACECASE8
return 1;
}
return 0;
|
8f0820 | 2014-08-28 | Per Hedbor | | }
|
c88c45 | 2018-05-17 | Stephen R. van den Berg | | static void io_discard_bufstart( Buffer *io )
{
if ( LIKELY(!io->locked_move) )
{
memmove( io->buffer, io_read_pointer(io), io_len(io) );
io->len -= io->offset;
io->num_move++;
io->offset = 0;
}
}
|
2c4241 | 2015-07-13 | Per Hedbor | | static void io_trim( Buffer *io )
{
|
38589a | 2015-08-27 | Per Hedbor | | if( !io->locked && io->malloced && (io->offset > 64 || io->len > 64) )
|
2c4241 | 2015-07-13 | Per Hedbor | | {
|
c88c45 | 2018-05-17 | Stephen R. van den Berg | | if( io->offset > 64 && io->offset > io_len(io) )
io_discard_bufstart(io);
|
2c4241 | 2015-07-13 | Per Hedbor | | if( io->len > 64 && ((io->allocated > (io->len)*(1.0+io->max_waste))))
{
void *new_ptr = xrealloc( io->buffer, io->len );
if( !new_ptr )
Pike_error(msg_out_of_mem_2, io->len);
io->buffer = new_ptr;
io->num_malloc++;
io->allocated = io->len;
}
}
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_unlink_external_storage( Buffer *io )
|
50c719 | 2014-09-10 | Per Hedbor | | ATTRIBUTE((noclone,noinline));
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_unlink_external_storage( Buffer *io )
|
50c719 | 2014-09-10 | Per Hedbor | | {
if( io->sub ) {
|
cb6501 | 2014-10-01 | Martin Nilsson | | io_unlock( get_storage(io->sub,Buffer_program ) );
|
50c719 | 2014-09-10 | Per Hedbor | | 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;
}
|
2eee2d | 2015-05-16 | Arne Goedeke | | static void io_ensure_malloced( Buffer *io, size_t bytes )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
if( UNLIKELY(!io->malloced) )
|
8cccac | 2014-08-28 | Per Hedbor | | {
/* convert to malloced buffer from a shared one. */
|
2c4241 | 2015-07-13 | Per Hedbor | | unsigned char *old = io->buffer;
|
2eee2d | 2015-05-16 | Arne Goedeke | |
|
2c4241 | 2015-07-13 | Per Hedbor | | bytes += io->len;
|
2eee2d | 2015-05-16 | Arne Goedeke | |
|
2c4241 | 2015-07-13 | Per Hedbor | | if (bytes < io->len || bytes + 100 < bytes)
|
2eee2d | 2015-05-16 | Arne Goedeke | | Pike_error(msg_out_of_mem_2, bytes + 100);
|
2c4241 | 2015-07-13 | Per Hedbor | | bytes += 100;
|
2eee2d | 2015-05-16 | Arne Goedeke | |
|
2c4241 | 2015-07-13 | Per Hedbor | | io->buffer = xalloc( bytes );
io->malloced = 1;
io->allocated = bytes;
io->num_malloc++;
memcpy( io->buffer, old, io->len );
io_unlink_external_storage(io);
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
fbc3bf | 2014-09-08 | Per Hedbor | | }
|
8cccac | 2014-08-28 | Per Hedbor | |
|
cb6501 | 2014-10-01 | Martin Nilsson | | static unsigned char *io_add_space_do_something( Buffer *io, size_t bytes, int force )
|
f3ed29 | 2014-09-11 | Per Hedbor | | ATTRIBUTE((noclone,noinline));
|
cb6501 | 2014-10-01 | Martin Nilsson | | static unsigned char *io_add_space_do_something( Buffer *io, size_t bytes, int force )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
|
401513 | 2014-09-15 | Per Hedbor | | if( bytes && io->len+bytes < io->len )
Pike_error("Too large buffer, can not have more than %lu bytes",
(size_t)-1);
|
fbc3bf | 2014-09-08 | Per Hedbor | | 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.
*
*/
|
7bd2c8 | 2018-05-22 | Henrik Grubbström (Grubba) | | if( UNLIKELY((force && io->offset) ||
(io_len(io) && io->offset > io->allocated / 2)) )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
c88c45 | 2018-05-17 | Stephen R. van den Berg | | /* 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.
*/
io_discard_bufstart(io);
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
317fc3 | 2014-09-02 | Per Hedbor | |
|
fbc3bf | 2014-09-08 | Per Hedbor | | if( UNLIKELY(io->len + bytes > io->allocated) )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
2c4241 | 2015-07-13 | Per Hedbor | | /* Actually grow the buffer. */
|
7b20a0 | 2015-07-21 | Arne Goedeke | | void *new_ptr;
|
2c4241 | 2015-07-13 | Per Hedbor | | size_t growth =
(io->allocated>>1) +
(io->allocated>>3);/* io->allocated * 0.625 */
|
fbc3bf | 2014-09-08 | Per Hedbor | |
|
2c4241 | 2015-07-13 | Per Hedbor | | if( growth < bytes )
growth = bytes + (bytes>>1);
|
fbc3bf | 2014-09-08 | Per Hedbor | |
|
2c4241 | 2015-07-13 | Per Hedbor | | if( io->allocated + growth < io->allocated )
{
growth = bytes+1;
if( io->allocated + growth < io->allocated )
Pike_error("Overflow in buffer size calculations\n");
}
|
7b20a0 | 2015-07-21 | Arne Goedeke | | new_ptr = xrealloc( io->buffer, io->allocated + growth );
|
3c0dee | 2015-05-15 | Tobias S. Josefowitz | | if( !new_ptr )
|
2c4241 | 2015-07-13 | Per Hedbor | | Pike_error(msg_out_of_mem_2, io->allocated+growth );
|
3c0dee | 2015-05-15 | Tobias S. Josefowitz | | io->buffer = new_ptr;
|
fbc3bf | 2014-09-08 | Per Hedbor | | io->num_malloc++;
|
2c4241 | 2015-07-13 | Per Hedbor | | io->allocated += growth;
|
8cccac | 2014-08-28 | Per Hedbor | | }
return io->buffer+io->len;
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static unsigned char *io_add_space( Buffer *io, size_t bytes, int force )
|
f3ed29 | 2014-09-11 | Per Hedbor | | {
if( io->len == io->offset )
io->offset = io->len = 0;
|
401513 | 2014-09-15 | Per Hedbor | | if( !force && io->malloced && !io->locked && io->len+bytes < io->allocated &&
(!bytes || io->len+bytes > io->len))
|
f3ed29 | 2014-09-11 | Per Hedbor | | return io->buffer+io->len;
return io_add_space_do_something( io, bytes, force );
}
|
317fc3 | 2014-09-02 | Per Hedbor | |
/*! @decl protected bool range_error( int howmuch )
*!
*! This function is called when an attempt is made to read out of bounds.
*!
|
6b6e7d | 2014-09-07 | Henrik Grubbström (Grubba) | | *! The default implementation simply returns @expr{0@} (zero).
|
317fc3 | 2014-09-02 | Per Hedbor | | *!
|
6b6e7d | 2014-09-07 | Henrik Grubbström (Grubba) | | *! Override this function to change the behavior.
*!
*! @param howmuch
|
317fc3 | 2014-09-02 | Per Hedbor | | *! The argument @[howmuch] indicates how much data is needed:
*!
|
6b6e7d | 2014-09-07 | Henrik Grubbström (Grubba) | | *! @int
*! @value 1..
*! Need @[howmuch] bytes more
|
611a8e | 2014-09-08 | Per Hedbor | | *! @value 0
|
6b6e7d | 2014-09-07 | Henrik 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.
|
317fc3 | 2014-09-02 | Per Hedbor | | *!
|
6b6e7d | 2014-09-07 | Henrik 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
|
317fc3 | 2014-09-02 | Per 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).
*/
|
89aecf | 2014-09-12 | Per Hedbor | | PIKEFUN int(0..1) range_error( int range )
|
317fc3 | 2014-09-02 | Per Hedbor | | flags ID_PROTECTED;
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
89aecf | 2014-09-12 | Per Hedbor | | Pike_sp[-1].u.integer = 0;
|
317fc3 | 2014-09-02 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_range_error_throw( Buffer *io, int howmuch )
|
fbc3bf | 2014-09-08 | Per Hedbor | | ATTRIBUTE((noclone,noinline));
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_range_error_throw( Buffer *io, int howmuch )
|
317fc3 | 2014-09-02 | Per Hedbor | | {
|
36b8e4 | 2014-11-24 | Per Hedbor | | if( io->error_mode )
{
struct object *err;
if( howmuch > 0 )
{
push_text("Trying to read %d bytes outside allowed range\n");
push_int(howmuch);
f_sprintf(2);
}
else
push_text("Illegal arguments\n");
if( io->error_mode != buffer_error_program )
|
317fc3 | 2014-09-02 | Per Hedbor | | {
|
36b8e4 | 2014-11-24 | Per Hedbor | | ref_push_object( io->this );
err = clone_object(io->error_mode,2);
|
317fc3 | 2014-09-02 | Per Hedbor | | }
|
36b8e4 | 2014-11-24 | Per Hedbor | | else
err = clone_object(io->error_mode,1);
push_object(err);
f_throw(1);
}
|
317fc3 | 2014-09-02 | Per Hedbor | | }
|
6a6820 | 2014-12-06 | Henrik Grubbström (Grubba) | | static struct pike_string *io_read_string( Buffer *io, ptrdiff_t len )
ATTRIBUTE((noclone,noinline));
|
cb6501 | 2014-10-01 | Martin Nilsson | | static size_t io_rewind( Buffer *io, INT_TYPE n );
|
8923ca | 2014-09-03 | Per Hedbor | |
|
fbc3bf | 2014-09-08 | Per Hedbor | | static void io_do_rewind_on_error( struct rewind_to *e )
{
e->io->locked_move--;
e->io->offset = e->rewind_to;
free( e );
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_rewind_on_error( Buffer *io, ONERROR *x )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
struct rewind_to *rew = xalloc( sizeof( struct rewind_to ) );
|
5fc94a | 2014-09-14 | Henrik Grubbström (Grubba) | | io->locked_move++;
|
fbc3bf | 2014-09-08 | Per Hedbor | | #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 );
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_unset_rewind_on_error( Buffer *io, ONERROR *x )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
|
50c719 | 2014-09-10 | Per Hedbor | | struct rewind_to *rew = x->arg;
|
4610bf | 2015-05-07 | Tobias S. Josefowitz | | #if defined(PIKE_DEBUG)
|
c00096 | 2014-09-08 | Henrik Grubbström (Grubba) | | if( io->locked_move != rew->old_locked_move )
|
fbc3bf | 2014-09-08 | Per Hedbor | | Pike_fatal( "Invalid io_rewind_on_error nesting\n");
|
50c719 | 2014-09-10 | Per Hedbor | | #endif
|
4610bf | 2015-05-07 | Tobias S. Josefowitz | | free( rew );
|
50c719 | 2014-09-10 | Per Hedbor | | UNSET_ONERROR( (*x) );
io->locked_move--;
|
fbc3bf | 2014-09-08 | Per Hedbor | | }
static void io_do_unwrite_on_error( struct rewind_to *e )
{
e->io->len = e->rewind_to;
free( e );
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_unwrite_on_error( Buffer *io, ONERROR *x )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
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 );
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_unset_unwrite_on_error( Buffer *UNUSED(io), ONERROR *x )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
UNSET_ONERROR( (*x) );
free( x->arg );
}
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | static ptrdiff_t io_call_write( Buffer *io, struct svalue *fun,
ptrdiff_t nbytes )
|
50c719 | 2014-09-10 | Per Hedbor | | ATTRIBUTE((noclone,noinline));
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_set_events( Buffer *io, struct my_file *fd, int extra, int set )
|
50c719 | 2014-09-10 | Per Hedbor | | ATTRIBUTE((noclone,noinline));
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_set_events( Buffer *UNUSED(io), struct my_file *fd, int extra, int set )
|
50c719 | 2014-09-10 | Per Hedbor | | {
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);
}
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | static ptrdiff_t io_call_write( Buffer *io, struct svalue *fun,
ptrdiff_t bytes )
|
50c719 | 2014-09-10 | Per Hedbor | | {
if( bytes > 0 )
{
|
5944b3 | 2014-09-11 | Henrik Grubbström (Grubba) | | ptrdiff_t l = 0;
|
fb869a | 2015-07-14 | Per Hedbor | | struct pike_string *s;
io->locked_move++;
s = io_read_string( io,bytes );
|
50c719 | 2014-09-10 | Per Hedbor | |
if( s )
{
io->output_triggered = 1;
push_string( s );
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | apply_svalue( fun, 1 );
if (UNLIKELY(TYPEOF(Pike_sp[-1]) != PIKE_T_INT)) {
|
fb869a | 2015-07-14 | Per Hedbor | | io->locked_move--;
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | Pike_error("Invalid return value from write callback.\n");
}
|
50c719 | 2014-09-10 | Per Hedbor | | l = Pike_sp[-1].u.integer;
pop_stack();
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | if( l < 0 )
|
50c719 | 2014-09-10 | Per Hedbor | | {
|
fb869a | 2015-07-14 | Per Hedbor | | io->locked_move--;
|
50c719 | 2014-09-10 | Per Hedbor | | io_rewind( io, bytes );
return -1;
}
|
130baa | 2014-10-03 | Per Hedbor | | if( bytes > l )
|
fb869a | 2015-07-14 | Per Hedbor | | {
|
50c719 | 2014-09-10 | Per Hedbor | | io_rewind( io, bytes-l );
|
fb869a | 2015-07-14 | Per Hedbor | | }
|
50c719 | 2014-09-10 | Per Hedbor | | }
|
fb869a | 2015-07-14 | Per Hedbor | | io->locked_move--;
|
50c719 | 2014-09-10 | Per Hedbor | | return l;
}
return -1;
}
|
9d1e8e | 2014-10-11 | Henrik Grubbström (Grubba) | | static ptrdiff_t io_actually_trigger_output( Buffer *io )
|
7c3477 | 2014-09-11 | Per Hedbor | | ATTRIBUTE((noclone,noinline));
|
9d1e8e | 2014-10-11 | Henrik Grubbström (Grubba) | | static ptrdiff_t io_actually_trigger_output( Buffer *io )
|
8923ca | 2014-09-03 | Per Hedbor | | {
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | 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);
|
9d1e8e | 2014-10-11 | Henrik Grubbström (Grubba) | | return 0;
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | }
ref = PTR_FROM_INT(prog, SUBTYPEOF(io->output));
inh = INHERIT_FROM_PTR(prog, ref);
if ((inh->prog == file_program) &&
(ref->identifier_offset == fd_write_identifier_offset)) {
/* Stdio.Fd::write */
struct my_file *fd =
get_inherit_storage( io->output.u.object, ref->inherit_offset );
|
7c3477 | 2014-09-11 | Per Hedbor | | io_set_events( io, fd, PIKE_BIT_FD_WRITE_OOB, PIKE_FD_WRITE );
io->output_triggered = 1;
|
9d1e8e | 2014-10-11 | Henrik Grubbström (Grubba) | | return 0;
|
50c719 | 2014-09-10 | Per Hedbor | | }
|
7c3477 | 2014-09-11 | Per Hedbor | | else
|
9d1e8e | 2014-10-11 | Henrik Grubbström (Grubba) | | return io_call_write( io, &io->output, MINIMUM( io_len(io), 100 ) );
|
7c3477 | 2014-09-11 | Per Hedbor | | }
|
9d1e8e | 2014-10-11 | Henrik Grubbström (Grubba) | | static ptrdiff_t io_trigger_output( Buffer *io )
|
7c3477 | 2014-09-11 | Per Hedbor | | {
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | if( UNLIKELY(io->output.u.object) && UNLIKELY(!io->output_triggered) )
|
9d1e8e | 2014-10-11 | Henrik Grubbström (Grubba) | | return io_actually_trigger_output(io);
return 0;
|
8923ca | 2014-09-03 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | static int io_range_error( Buffer *io, ptrdiff_t howmuch )
|
fbc3bf | 2014-09-08 | Per Hedbor | | ATTRIBUTE((noclone,noinline));
|
cb6501 | 2014-10-01 | Martin Nilsson | | static int io_range_error( Buffer *io, ptrdiff_t howmuch )
|
317fc3 | 2014-09-02 | Per Hedbor | | {
int res;
struct svalue *osp = Pike_sp;
|
fbc3bf | 2014-09-08 | Per Hedbor | | push_int64( howmuch );
|
cb6501 | 2014-10-01 | Martin Nilsson | | apply_current( f_Buffer_range_error_fun_num, 1 );
|
317fc3 | 2014-09-02 | Per Hedbor | | res = Pike_sp[-1].u.integer;
pop_n_elems( Pike_sp-osp );
if( !res ) io_range_error_throw( io, howmuch );
return res;
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | static int io_avail( Buffer *io, ptrdiff_t len )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
ebd1d4 | 2014-09-14 | Per Hedbor | | if( len < 0 || len + io->offset > io->len )
{
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);
|
317fc3 | 2014-09-02 | Per Hedbor | | return 0;
|
ebd1d4 | 2014-09-14 | Per Hedbor | | }
|
8cccac | 2014-08-28 | Per Hedbor | | return 1;
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static int io_avail_mul( Buffer *io, ptrdiff_t len, ptrdiff_t each )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
/* safely check if len*each is available. */
|
ebd1d4 | 2014-09-14 | Per Hedbor | | 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);
|
fbc3bf | 2014-09-08 | Per Hedbor | | return 0;
|
ebd1d4 | 2014-09-14 | Per Hedbor | | }
|
fbc3bf | 2014-09-08 | Per Hedbor | | return 1;
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_append( Buffer *io, const void *p, size_t bytes )
|
8cccac | 2014-08-28 | Per Hedbor | | {
memcpy( io_add_space( io, bytes, 0 ), p, bytes );
io->len += bytes;
|
8923ca | 2014-09-03 | Per Hedbor | | io_trigger_output( io );
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | static size_t io_read( Buffer *io, void *to, size_t len )
|
8cccac | 2014-08-28 | Per Hedbor | | {
if( !io_avail(io,len))
return 0;
memcpy( to, io_read_pointer(io), len );
io_consume( io, len );
return len;
}
|
6a6820 | 2014-12-06 | Henrik Grubbström (Grubba) | | static struct pike_string *io_read_string( Buffer *io, ptrdiff_t len )
|
8cccac | 2014-08-28 | Per Hedbor | | {
struct pike_string *s;
if( len > 0x7fffffff )
Pike_error("This region is too large to convert to a string.\n");
|
fbc3bf | 2014-09-08 | Per Hedbor | |
|
401513 | 2014-09-15 | Per Hedbor | | if( len < 0 )
return make_shared_binary_string(NULL,0);
|
fbc3bf | 2014-09-08 | Per Hedbor | | if( !io_avail(io,len))
return NULL;
|
8cccac | 2014-08-28 | Per Hedbor | | s = begin_shared_string( len );
|
317fc3 | 2014-09-02 | Per Hedbor | | io_read( io, s->str, len );
|
8cccac | 2014-08-28 | Per Hedbor | | return end_shared_string(s);
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static struct object *io_read_buffer( Buffer *io, size_t len, int do_copy )
|
8cccac | 2014-08-28 | Per Hedbor | | {
struct object *b;
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *to;
|
8cccac | 2014-08-28 | Per Hedbor | | if( !io_avail(io,len))
return NULL;
|
cb6501 | 2014-10-01 | Martin Nilsson | | b = low_clone( Buffer_program );
|
f7b625 | 2017-06-16 | Marcus Agehall | | call_c_initializers(b);
|
cb6501 | 2014-10-01 | Martin Nilsson | | to = get_storage(b,Buffer_program);
|
8cccac | 2014-08-28 | Per Hedbor | |
io_lock( io );
to->buffer = io_read_pointer(io);
to->len = len;
to->sub = Pike_fp->current_object;
|
929b28 | 2014-09-18 | Henrik Grubbström (Grubba) | | add_ref(to->sub);
|
8cccac | 2014-08-28 | Per Hedbor | | io_consume( io, len );
if( do_copy )
|
fbc3bf | 2014-09-08 | Per Hedbor | | io_ensure_malloced( to, 0 );
|
8cccac | 2014-08-28 | Per Hedbor | |
return b;
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static int io_read_byte_uc( Buffer *io )
|
8cccac | 2014-08-28 | Per Hedbor | | {
return io->buffer[io->offset++];
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static INT_TYPE io_read_number_uc( Buffer *io, size_t len )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
fbc3bf | 2014-09-08 | Per Hedbor | | size_t i;
|
ebd1d4 | 2014-09-14 | Per Hedbor | | LONGEST res = 0;
for( i=0; i<len; i++ )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
res <<= 8;
res |= io_read_byte_uc(io);
}
return res;
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | static INT_TYPE io_read_signed_number_uc( Buffer *io, size_t len )
|
ae81d2 | 2014-09-18 | Per Hedbor | | {
size_t i;
INT_TYPE res = 0;
if( !len ) return 0;
len--;
res = io_read_byte_uc(io);
if( res & 0x80 )
|
7bd2c8 | 2018-05-22 | Henrik Grubbström (Grubba) | | res |= ~(INT_TYPE)0xff;
|
ae81d2 | 2014-09-18 | Per Hedbor | | for( i=0; i<len; i++ )
{
res <<= 8;
res |= io_read_byte_uc(io);
}
return res;
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static LONGEST io_read_number( Buffer *io, size_t len )
|
8cccac | 2014-08-28 | Per Hedbor | | {
LONGEST res;
|
ebd1d4 | 2014-09-14 | Per Hedbor | | if( !io_avail(io, len) )
return -1;
|
00e28b | 2014-10-02 | Per Hedbor | | /* ensure only leading 0:s */
|
82a99c | 2014-09-14 | Stephen R. van den Berg | | for (; UNLIKELY(len > SIZEOF_INT_TYPE); len--)
if( UNLIKELY(io_read_byte_uc(io)) )
Pike_error("Integer (%dbit) overflow.\n", SIZEOF_INT_TYPE*8);
res = io_read_number_uc( io, len );
if ( UNLIKELY(res < 0) )
Pike_error("Signed (%dbit) overflow.\n", SIZEOF_INT_TYPE*8);
return res;
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | static struct object *io_read_bignum( Buffer *io, size_t len )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
ae81d2 | 2014-09-18 | Per Hedbor | | struct object *o;
MP_INT *i;
unsigned char *p;
|
8cccac | 2014-08-28 | Per Hedbor | | LONGEST res;
|
ae81d2 | 2014-09-18 | Per Hedbor | |
if( !io_avail(io,len) ) return NULL;
o = fast_clone_object(get_auto_bignum_program());
i = (void*)o->storage;
mpz_import( i, len, 1, 1, 0, 0, io_read_pointer(io) );
io_consume(io,len);
return o;
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_add_bignum( Buffer *io, struct object *o, int width )
|
7c8944 | 2014-09-11 | Per Hedbor | | ATTRIBUTE((noclone,noinline));
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_add_bignum( Buffer *io, struct object *o, int width )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
ae81d2 | 2014-09-18 | Per Hedbor | | MP_INT *i = (void*)o->storage;
MP_INT tmp;
int free;
|
7c8944 | 2014-09-11 | Per Hedbor | | unsigned char*d;
struct pike_string *s;
|
ae81d2 | 2014-09-18 | Per Hedbor | | int pad = 0;
|
6a6820 | 2014-12-06 | Henrik Grubbström (Grubba) | | ptrdiff_t bytes;
|
ae81d2 | 2014-09-18 | Per Hedbor | | size_t exp;
|
fbc3bf | 2014-09-08 | Per Hedbor | |
|
ae81d2 | 2014-09-18 | Per Hedbor | | if( mpz_sgn( i ) < 0 )
{
mpz_init( &tmp );
mpz_add_ui( &tmp, i, 1);
pad = 0xff;
i = &tmp;
}
|
fbc3bf | 2014-09-08 | Per Hedbor | |
|
ae81d2 | 2014-09-18 | Per Hedbor | | bytes = (mpz_sizeinbase( i, 2 )+7) / 8;
|
fbc3bf | 2014-09-08 | Per Hedbor | |
|
ae81d2 | 2014-09-18 | Per Hedbor | | if( bytes > width )
|
fbc3bf | 2014-09-08 | Per Hedbor | | Pike_error("Number too large to store in %d bits\n", width*8);
|
7c8944 | 2014-09-11 | Per Hedbor | | d = io_add_space( io, width, 0 );
io->len += width;
|
ae81d2 | 2014-09-18 | Per Hedbor | | if( width > bytes )
{
memset( d, pad, width-bytes );
d += width-bytes;
}
mpz_export( d, &exp, 1, 1, 1, 0, i );
if( !exp )
{
/* if i is 0 mpz_export will not write anything.
Handle that by zeroing the byte that should have been written.
*/
#ifdef PIKE_DEBUG
if( bytes != 1 )
Pike_fatal("Oddities abound\n");
#endif
*d = pad;
}
if( pad )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
|
ae81d2 | 2014-09-18 | Per Hedbor | | while(exp--)
*d++ ^= 0xff; /* pad, but that is 0xff */
mpz_clear(&tmp);
|
fbc3bf | 2014-09-08 | Per Hedbor | | }
|
eb5a99 | 2017-09-24 | Arne Goedeke | | io_trigger_output( io );
|
fbc3bf | 2014-09-08 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_add_int_uc( Buffer *io, ptrdiff_t i, size_t bytes )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
|
73599d | 2014-09-08 | Per Hedbor | | unsigned char *x = io->buffer+io->len;
|
8cccac | 2014-08-28 | Per Hedbor | | io->len += bytes;
while(bytes--)
{
|
8b6536 | 2014-09-11 | Stephen R. van den Berg | | x[bytes] = i;
|
8cccac | 2014-08-28 | Per Hedbor | | i>>=8;
}
|
fbc3bf | 2014-09-08 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | static size_t io_add_int( Buffer *io, ptrdiff_t i, size_t bytes )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
|
ae81d2 | 2014-09-18 | Per Hedbor | | io_add_space(io, bytes, 0);
|
fbc3bf | 2014-09-08 | Per Hedbor | | io_add_int_uc( io, i, bytes );
|
8923ca | 2014-09-03 | Per Hedbor | | io_trigger_output( io );
|
8cccac | 2014-08-28 | Per Hedbor | | return io_len( io );
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static size_t io_rewind( Buffer *io, INT_TYPE n )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
ebd1d4 | 2014-09-14 | Per Hedbor | | if( n < 0 || (io->offset < (unsigned)n) )
{
if( n < 0 )
io_range_error_throw( io, 0 );
else if( io_range_error(io,-(long)(n-io->offset)) )
return io_rewind( io, n );
return -1;
}
|
8cccac | 2014-08-28 | Per Hedbor | | io->offset -= n;
|
8923ca | 2014-09-03 | Per Hedbor | | io_trigger_output( io );
|
8cccac | 2014-08-28 | Per Hedbor | | return io->offset;
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_append_byte_uc( Buffer *io, unsigned char byte )
|
342f56 | 2014-09-02 | Per Hedbor | | {
io->buffer[io->len++] = byte;
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_append_short_uc( Buffer *io, unsigned short shrt )
|
342f56 | 2014-09-02 | Per Hedbor | | {
|
e6ed8e | 2014-12-06 | Marcus Comstedt | | io->buffer[io->len++] = shrt>>8;
io->buffer[io->len++] = shrt;
|
342f56 | 2014-09-02 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_append_int_uc( Buffer *io, unsigned INT32 i )
|
342f56 | 2014-09-02 | Per Hedbor | | {
|
e6ed8e | 2014-12-06 | Marcus Comstedt | | io->buffer[io->len++] = i>>24;
io->buffer[io->len++] = i>>16;
io->buffer[io->len++] = i>>8;
io->buffer[io->len++] = i;
|
342f56 | 2014-09-02 | Per Hedbor | | }
|
fbc3bf | 2014-09-08 | Per Hedbor | |
|
bda893 | 2014-10-16 | Stephen R. van den Berg | | static size_t io_svalue_len( Buffer *io, struct svalue *p )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
|
bda893 | 2014-10-16 | Stephen R. van den Berg | | switch( TYPEOF(*p) ) {
case PIKE_T_INT:
return 1;
case PIKE_T_STRING:
if( !p->u.string->size_shift )
return p->u.string->len;
break;
case PIKE_T_ARRAY: {
size_t len;
struct array *argp = p->u.array;
INT_TYPE i;
DECLARE_CYCLIC();
if (BEGIN_CYCLIC(io, argp))
Pike_error("Attempt to append a cyclic array to a buffer.\n");
for(len=i=0; i<argp->size; i++ )
len += io_svalue_len( io, argp->item+i );
END_CYCLIC();
|
f3ed29 | 2014-09-11 | Per Hedbor | | return len;
|
bda893 | 2014-10-16 | Stephen R. van den Berg | | }
case PIKE_T_OBJECT: {
size_t len;
if( get_memory_object_memory( p->u.object, NULL, &len, NULL ) )
return len;
break;
}
|
50c719 | 2014-09-10 | Per Hedbor | | }
|
f3ed29 | 2014-09-11 | Per Hedbor | | Pike_error("Illegal argument (not an 8bit string or 8bit buffer object)\n");
|
fbc3bf | 2014-09-08 | Per Hedbor | | }
/* NOTE: Can return negative integers. */
|
50c719 | 2014-09-10 | Per Hedbor | | static INT_TYPE get_small_int( struct svalue *s )
ATTRIBUTE((noclone,noinline));
|
342f56 | 2014-09-02 | Per Hedbor | | static INT_TYPE get_small_int( struct svalue *s )
{
|
50c719 | 2014-09-10 | Per 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");
|
342f56 | 2014-09-02 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_append_svalue( Buffer *io, struct svalue *p )
|
f3ed29 | 2014-09-11 | Per Hedbor | | ATTRIBUTE((noinline));
|
cb6501 | 2014-10-01 | Martin Nilsson | | static void io_append_svalue( Buffer *io, struct svalue *p )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
switch( TYPEOF(*p) )
{
case PIKE_T_STRING:
{
struct pike_string *s = p->u.string;
|
973a69 | 2014-09-10 | Henrik Grubbström (Grubba) | | if( !s->len ) return;
|
cb6501 | 2014-10-01 | Martin Nilsson | | if( s->size_shift ) Pike_error("Buffer only handles 8bit data\n");
|
fbc3bf | 2014-09-08 | Per Hedbor | | if( !io->buffer )
{
|
973a69 | 2014-09-10 | Henrik Grubbström (Grubba) | | #ifdef PIKE_DEBUG
|
cb6501 | 2014-10-01 | Martin Nilsson | | if (io->str) Pike_fatal("Buffer with string but NULL buffer.\n");
|
973a69 | 2014-09-10 | Henrik Grubbström (Grubba) | | #endif
|
fbc3bf | 2014-09-08 | Per Hedbor | | io->str = s;
io->buffer = (unsigned char*)s->str;
io->len = s->len;
|
929b28 | 2014-09-18 | Henrik Grubbström (Grubba) | | add_ref(s);
|
eee36d | 2015-02-23 | Arne Goedeke | | io_trigger_output( io );
|
fbc3bf | 2014-09-08 | Per Hedbor | | }
else
io_append( io, s->str, s->len );
}
break;
case PIKE_T_ARRAY:
{
struct array *argp = p->u.array;
INT_TYPE i;
|
3ecc99 | 2014-09-08 | Henrik Grubbström (Grubba) | | DECLARE_CYCLIC();
if (BEGIN_CYCLIC(io, argp))
Pike_error("Attempt to append a cyclic array to a buffer.\n");
|
fbc3bf | 2014-09-08 | Per Hedbor | | for(i=0; i<argp->size; i++ )
io_append_svalue( io, argp->item+i );
|
3ecc99 | 2014-09-08 | Henrik Grubbström (Grubba) | |
END_CYCLIC();
|
fbc3bf | 2014-09-08 | Per Hedbor | | }
break;
case PIKE_T_OBJECT:
{
|
f3ed29 | 2014-09-11 | Per Hedbor | | size_t len;
void *ptr;
struct sysmem *s;
enum memobj_type t = get_memory_object_memory( p->u.object, &ptr, &len, NULL );
if( !io->buffer && t==MEMOBJ_SYSTEM_MEMORY )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
|
f3ed29 | 2014-09-11 | Per Hedbor | | io->buffer = ptr;
io->len = len;
io->source = p->u.object;
|
929b28 | 2014-09-18 | Henrik Grubbström (Grubba) | | add_ref(io->source);
|
f3ed29 | 2014-09-11 | Per Hedbor | | return;
|
fbc3bf | 2014-09-08 | Per Hedbor | | }
|
f3ed29 | 2014-09-11 | Per Hedbor | | if( t != MEMOBJ_NONE )
io_append( io, ptr, len );
|
fbc3bf | 2014-09-08 | Per Hedbor | | else
|
f3ed29 | 2014-09-11 | Per Hedbor | | Pike_error("Unsupported argument type\n");
|
fbc3bf | 2014-09-08 | Per Hedbor | | }
break;
case PIKE_T_INT:
{
unsigned char a = p->u.integer;
io_append( io, &a, 1 );
}
}
}
|
342f56 | 2014-09-02 | Per Hedbor | |
|
fbc3bf | 2014-09-08 | Per Hedbor | | #undef THIS
|
cb6501 | 2014-10-01 | Martin Nilsson | | #define THIS (&(((struct Buffer_struct *)Pike_fp->current_storage)->b))
|
342f56 | 2014-09-02 | Per Hedbor | |
|
8cccac | 2014-08-28 | Per Hedbor | | /* pike functions */
|
e16861 | 2014-10-01 | Henrik Grubbström (Grubba) | | /*! @decl int(-1..) input_from( Stdio.Stream f, int|void nbytes )
|
8b141e | 2014-09-01 | Per Hedbor | | *!
|
559c92 | 2014-09-03 | Per Hedbor | | *! Read data from @[f] into this buffer. If @[nbytes] is not
*! specified, read until there is no more data to read (currently).
|
317fc3 | 2014-09-02 | Per Hedbor | | *!
|
e16861 | 2014-10-01 | Henrik Grubbström (Grubba) | | *! Returns the amount of data that was read, or @expr{-1@} on
*! read error.
|
317fc3 | 2014-09-02 | Per Hedbor | | *!
*! @note
*! Please note that this funcition will read all data from the
*! filedescriptor unless it's set to be non-blocking.
|
8b141e | 2014-09-01 | Per Hedbor | | */
|
e16861 | 2014-10-01 | Henrik Grubbström (Grubba) | | PIKEFUN int(-1..) input_from( object f, int|void _nbytes, int|void _once )
|
8b141e | 2014-09-01 | Per Hedbor | | {
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
8b141e | 2014-09-01 | Per Hedbor | | size_t sz = io_len( io );
|
559c92 | 2014-09-03 | Per Hedbor | | size_t bread = 0, nbytes = (size_t)-1;
|
8b141e | 2014-09-01 | Per Hedbor | | struct my_file *fd;
|
432a82 | 2014-09-04 | Per Hedbor | | int once = 0;
|
8b141e | 2014-09-01 | Per Hedbor | |
|
598983 | 2014-10-09 | Henrik Grubbström (Grubba) | | if( _nbytes && (SUBTYPEOF(*_nbytes) == NUMBER_NUMBER) ) {
|
559c92 | 2014-09-03 | Per Hedbor | | nbytes = _nbytes->u.integer;
|
e16861 | 2014-10-01 | Henrik Grubbström (Grubba) | | if (!nbytes) RETURN 0;
}
|
559c92 | 2014-09-03 | Per Hedbor | |
|
432a82 | 2014-09-04 | Per Hedbor | | if( _once )
once = _once->u.integer;
|
8b141e | 2014-09-01 | Per Hedbor | | if( (fd = get_storage( f, file_program )) )
{
while( 1 )
{
|
49c1b7 | 2018-05-17 | Stephen R. van den Berg | | unsigned char *ptr = io_add_space( io, READ_CHUNKSIZE, 0 );
|
8b141e | 2014-09-01 | Per Hedbor | | int res;
|
49c1b7 | 2018-05-17 | Stephen R. van den Berg | | res = fd_read( fd->box.fd, ptr, MINIMUM(READ_CHUNKSIZE, nbytes) );
|
8b141e | 2014-09-01 | Per Hedbor | |
if( res == -1 && errno == EINTR )
continue;
if( res <= 0 )
break;
|
432a82 | 2014-09-04 | Per Hedbor | |
|
559c92 | 2014-09-03 | Per Hedbor | | nbytes -= res;
|
8b141e | 2014-09-01 | Per Hedbor | | io->len += res;
bread += res;
|
49c1b7 | 2018-05-17 | Stephen R. van den Berg | | if( res != READ_CHUNKSIZE || once || !nbytes )
|
8b141e | 2014-09-01 | Per Hedbor | | break;
}
|
50c719 | 2014-09-10 | Per Hedbor | | io_set_events( io, fd, PIKE_BIT_FD_READ_OOB, PIKE_FD_READ );
|
8b141e | 2014-09-01 | Per Hedbor | | }
else
{
|
559c92 | 2014-09-03 | Per Hedbor | | /* some other object. Just call read */
while( nbytes )
|
8b141e | 2014-09-01 | Per Hedbor | | {
|
49c1b7 | 2018-05-17 | Stephen R. van den Berg | | push_int( MINIMUM(READ_CHUNKSIZE, nbytes) );
|
8b141e | 2014-09-01 | Per 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 );
|
559c92 | 2014-09-03 | Per Hedbor | | nbytes -= Pike_sp[-1].u.string->len;
|
8b141e | 2014-09-01 | Per Hedbor | | pop_stack();
}
}
|
e16861 | 2014-10-01 | Henrik Grubbström (Grubba) | |
if (!bread) RETURN -1;
|
b5183d | 2017-09-24 | Arne Goedeke | | io_trigger_output( io );
|
8b141e | 2014-09-01 | Per Hedbor | | RETURN bread;
}
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | /*! @decl int __fd_set_output( object|function(string:int) write_callback )
|
8923ca | 2014-09-03 | Per Hedbor | | *!
*! 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.
|
fbc3bf | 2014-09-08 | Per Hedbor | | *!
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | *! If @[write_callback] is @expr{0@} (zero) the state is cleared.
|
8923ca | 2014-09-03 | Per Hedbor | | */
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | PIKEFUN void __fd_set_output( int(0..0)|object|function f )
|
8923ca | 2014-09-03 | Per Hedbor | | {
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | if( TYPEOF(*f) == PIKE_T_OBJECT ) {
struct program *p = f->u.object->prog;
if (p) {
struct inherit *inh = p->inherits + SUBTYPEOF(*f);
int write_fun_num;
p = inh->prog;
if ((write_fun_num = find_identifier("write", p)) == -1) {
Pike_error("Function \"write\" not available in object.\n");
}
SET_SVAL_TYPE_SUBTYPE(*f, PIKE_T_FUNCTION, write_fun_num);
}
} else if (TYPEOF(*f) != PIKE_T_FUNCTION) {
push_int(0);
f = Pike_sp-1;
|
50c719 | 2014-09-10 | Per Hedbor | | }
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | assign_svalue(&io->output, f);
io->output_triggered = 0;
|
8923ca | 2014-09-03 | Per Hedbor | | }
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | /*! @decl int(-1..) output_to( Stdio.Stream|function(string:int) fun, @
*! int(0..)|void nbytes )
|
540b6c | 2014-09-01 | Per Hedbor | | *!
*! Write data from the buffer to the indicated file.
*!
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | *! @param fun
*! Write function. Either one of:
*! @mixed
*! @type Stdio.Stream
*! A file object in which the function @expr{write()@} will
*! be called.
*! @type function(string:int)
*! A function which will be called with a @expr{string(8bit)@}
*! to write and is expected to return an @expr{int@} indicating
*! the number of bytes successfully written or @expr{-1@} on
*! failure.
*! @endmixed
*!
|
2062be | 2014-09-09 | Henrik Grubbström (Grubba) | | *! @param nbytes
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | *! If @[nbytes] is not specified the whole buffer will be written
*! if possible. Otherwise at most @[nbytes] will be written.
|
2062be | 2014-09-09 | Henrik Grubbström (Grubba) | | *!
*! @returns
|
b06488 | 2014-09-11 | Stephen R. van den Berg | | *! Will return the number of bytes that have been written successfully.
|
2062be | 2014-09-09 | Henrik Grubbström (Grubba) | | *!
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | *! If no bytes have been written successfully and @expr{fun()@} failed
|
b06488 | 2014-09-11 | Stephen R. van den Berg | | *! with an error, @expr{-1@} will be returned.
|
540b6c | 2014-09-01 | Per Hedbor | | */
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | PIKEFUN int(-1..) output_to( object|function(string:int) f, int|void nbytes )
|
540b6c | 2014-09-01 | Per Hedbor | | {
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
04a10d | 2014-10-02 | Martin Nilsson | | ptrdiff_t written = 0;
|
5944b3 | 2014-09-11 | Henrik Grubbström (Grubba) | | ptrdiff_t sz = io_len( io );
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | int write_fun_num = -1;
|
fbc3bf | 2014-09-08 | Per Hedbor | |
|
559c92 | 2014-09-03 | Per Hedbor | | if( !sz )
|
cd79ef | 2014-09-03 | Per Hedbor | | {
|
50c719 | 2014-09-10 | Per Hedbor | | io_range_error(io, sz);
sz = io_len(io);
|
cd79ef | 2014-09-03 | Per Hedbor | | }
|
598983 | 2014-10-09 | Henrik Grubbström (Grubba) | | if( nbytes && (SUBTYPEOF(*nbytes) == NUMBER_NUMBER) )
|
04a10d | 2014-10-02 | Martin Nilsson | | sz = MINIMUM(nbytes->u.integer, sz);
|
559c92 | 2014-09-03 | Per Hedbor | |
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | if( TYPEOF(*f) == PIKE_T_OBJECT ) {
struct program *p = f->u.object->prog;
if (LIKELY(p)) {
struct inherit *inh = p->inherits + SUBTYPEOF(*f);
p = inh->prog;
if ((write_fun_num = find_identifier("write", p)) == -1) {
Pike_error("Function \"write\" not available in object.\n");
}
SET_SVAL_TYPE_SUBTYPE(*f, PIKE_T_FUNCTION, write_fun_num);
} else {
SIMPLE_BAD_ARG_ERROR("output_to", 1, "object|function");
}
} else if (UNLIKELY(TYPEOF(*f) != PIKE_T_FUNCTION)) {
SIMPLE_BAD_ARG_ERROR("output_to", 1, "object|function");
} else {
write_fun_num = SUBTYPEOF(*f);
}
if (write_fun_num != FUNCTION_BUILTIN) {
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 )
{
|
49c1b7 | 2018-05-17 | Stephen R. van den Berg | | ptrdiff_t rd = MINIMUM(sz-written, WRITE_CHUNKSIZE);
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | 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;
}
io_consume( io, res );
written += res;
io_set_events( io, fd, PIKE_BIT_FD_WRITE_OOB, PIKE_FD_WRITE);
}
RETURN written;
|
540b6c | 2014-09-01 | Per Hedbor | | }
}
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | |
/* Some other object or function. Just call it. */
while( sz > written )
|
540b6c | 2014-09-01 | Per Hedbor | | {
|
49c1b7 | 2018-05-17 | Stephen R. van den Berg | | size_t rd = MINIMUM(sz-written, WRITE_CHUNKSIZE);
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | ptrdiff_t wr = io_call_write( io, f, rd );
if( wr <= 0 )
|
540b6c | 2014-09-01 | Per Hedbor | | {
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | if (!written) written = -1;
break;
|
540b6c | 2014-09-01 | Per Hedbor | | }
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | written += wr;
|
49c1b7 | 2018-05-17 | Stephen R. van den Berg | | if( wr < WRITE_CHUNKSIZE )
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | break;
|
540b6c | 2014-09-01 | Per Hedbor | | }
RETURN written;
}
|
9d1e8e | 2014-10-11 | Henrik Grubbström (Grubba) | | /*! @decl int(-1..) try_output()
*!
*! Try to write some data from the buffer to the file
*! registered with @[__fd_set_output()].
*!
*! This is typically called from backend callbacks when it
*! seems that it is possible to write some data to the file.
*!
*! @returns
*! Returns @expr{-1@} on write error, and otherwise
*! the number of bytes written to the file.
*!
*! @seealso
*! @[__fd_set_output()]
*/
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;
}
|
ae81d2 | 2014-09-18 | Per Hedbor | | /*! @decl int read_sint( int size )
*!
*! 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 )
{
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
ae81d2 | 2014-09-18 | Per Hedbor | | struct pike_string *tmp;
Pike_sp--;
if( !io_avail( io, nbytes ) )
{
push_undefined();
return;
}
if( nbytes <= SIZEOF_INT_TYPE )
{
push_int( io_read_signed_number_uc( io,nbytes ) );
return;
}
// It's a bignum.
// We should probably optimize this. :)
tmp = io_read_string( io, nbytes );
if( tmp->str[0]&0x80 )
{
push_int(-1);
push_int( nbytes * 8 );
o_lsh();
}
ref_push_string( tmp );
push_int( 256 );
push_object( clone_object( get_auto_bignum_program(), 2 ) );
if( tmp->str[0]&0x80 )
o_xor();
free_string( tmp );
}
|
9629ad | 2014-09-01 | Per Hedbor | | PIKEFUN int(0..) _size_object( )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
2c4241 | 2015-07-13 | Per Hedbor | | RETURN THIS->malloced ? THIS->allocated : 0;
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
54bcdc | 2015-05-15 | Tobias S. Josefowitz | | /*! @decl Buffer add_padding( int(0..) nbytes, int(0..255)|void byte )
|
ae81d2 | 2014-09-18 | Per Hedbor | | *!
*! 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.
*/
|
54bcdc | 2015-05-15 | Tobias S. Josefowitz | | PIKEFUN Buffer add_padding( int(0..) nbytes, int|void _byte )
|
ae81d2 | 2014-09-18 | Per Hedbor | | {
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
ae81d2 | 2014-09-18 | Per Hedbor | | int byte = 0;
if( _byte ) byte = _byte->u.integer;
|
54bcdc | 2015-05-15 | Tobias S. Josefowitz | |
if( nbytes < 0 )
Pike_error("Cannot add negative padding.\n");
|
ae81d2 | 2014-09-18 | Per Hedbor | | memset( io_add_space( io, nbytes,0), byte, nbytes );
|
7db9b0 | 2015-05-15 | Tobias S. Josefowitz | | io->len += nbytes;
|
ae81d2 | 2014-09-18 | Per Hedbor | | Pike_sp -= args;
|
eb5a99 | 2017-09-24 | Arne Goedeke | | io_trigger_output( io );
|
ae81d2 | 2014-09-18 | Per Hedbor | | ref_push_object( io->this );
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | /*! @decl Buffer add( AddArgument ... data )
|
fbc3bf | 2014-09-08 | Per Hedbor | | *! @code
|
cb6501 | 2014-10-01 | Martin Nilsson | | *! private typedef @[System.Memory]|@[Stdio.Buffer]|@[String.Buffer] BufferObject;
|
fbc3bf | 2014-09-08 | Per Hedbor | | *! private typedef BufferObject|string(8bit)|int(8bit)|array(AddArgument) AddArgument;
*! @endcode
|
8cccac | 2014-08-28 | Per Hedbor | | *!
|
8b141e | 2014-09-01 | Per Hedbor | | *! Add the items in data to the end of the buffer.
|
fbc3bf | 2014-09-08 | Per Hedbor | | *!
*! The supported argument types are:
*!
|
d4c85e | 2014-09-08 | Henrik 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.
|
cb6501 | 2014-10-01 | Martin Nilsson | | *! @type Stdio.Buffer
|
d4c85e | 2014-09-08 | Henrik Grubbström (Grubba) | | *! 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
|
8b141e | 2014-09-01 | Per Hedbor | | *!
|
342f56 | 2014-09-02 | Per Hedbor | | *! @seealso
|
8b141e | 2014-09-01 | Per Hedbor | | *! @[sprintf], @[add_int8], @[add_int16], @[add_int32], @[add_int]
*! and
*! @[add_hstring]
|
8cccac | 2014-08-28 | Per Hedbor | | */
|
cb6501 | 2014-10-01 | Martin Nilsson | | PIKEFUN Buffer add( object|string|int|array(object|string|int) ... argp)
|
8cccac | 2014-08-28 | Per Hedbor | | {
int i;
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
fbc3bf | 2014-09-08 | Per Hedbor | |
|
8cccac | 2014-08-28 | Per Hedbor | | for(i=0; i<args; i++ )
|
fbc3bf | 2014-09-08 | Per Hedbor | | io_append_svalue( io, argp+i );
|
8b141e | 2014-09-01 | Per Hedbor | |
|
fbc3bf | 2014-09-08 | Per Hedbor | | pop_stack();
|
317fc3 | 2014-09-02 | Per Hedbor | | ref_push_object(io->this);
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | /*! @decl Buffer add_int8( int(0..255) )
|
8cccac | 2014-08-28 | Per Hedbor | | *! Adds a single byte to the buffer.
*/
|
cb6501 | 2014-10-01 | Martin Nilsson | | PIKEFUN Buffer add_int8( int i )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
f3ed29 | 2014-09-11 | Per Hedbor | | *io_add_space(io,1,0)=i;
io->len++;
Pike_sp--;
|
b5183d | 2017-09-24 | Arne Goedeke | | io_trigger_output( io );
|
317fc3 | 2014-09-02 | Per Hedbor | | ref_push_object(Pike_fp->current_object);
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | /*! @decl Buffer add_int16( int(0..65535) )
|
8cccac | 2014-08-28 | Per Hedbor | | *!
*! Add a 16-bit network byte order value to the buffer
*/
|
cb6501 | 2014-10-01 | Martin Nilsson | | PIKEFUN Buffer add_int16( int i )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
f3ed29 | 2014-09-11 | Per Hedbor | | unsigned char *p = io_add_space(io,2,0);
p[0] = i>>8;
p[1] = i;
io->len += 2;
|
b5183d | 2017-09-24 | Arne Goedeke | | io_trigger_output( io );
|
317fc3 | 2014-09-02 | Per Hedbor | | ref_push_object(Pike_fp->current_object);
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | /*! @decl Buffer add_int32( int i )
|
8cccac | 2014-08-28 | Per Hedbor | | *! Adds a 32 bit network byte order value to the buffer
*/
|
cb6501 | 2014-10-01 | Martin Nilsson | | PIKEFUN Buffer add_int32( int i )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
f3ed29 | 2014-09-11 | Per Hedbor | | 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;
|
b5183d | 2017-09-24 | Arne Goedeke | | io_trigger_output( io );
|
317fc3 | 2014-09-02 | Per Hedbor | | ref_push_object(Pike_fp->current_object);
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | /*! @decl Buffer add_hstring( string(0..255) 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 )
|
7772e6 | 2014-09-29 | Stephen R. van den Berg | | *! @decl Buffer add_hstring( int(0..255) data, int size_size )
|
cb6501 | 2014-10-01 | Martin Nilsson | | *! @decl Buffer add_hstring( array data, int size_size )
|
fb3fa9 | 2014-11-10 | Stephen R. van den Berg | | *! @decl Buffer add_hstring( int|string(0..255)|Stdio.Buffer|System.Memory|array data, int size_size, int offset )
|
8cccac | 2014-08-28 | Per Hedbor | | *!
|
50c719 | 2014-09-10 | Per Hedbor | | *! Adds length of data followed by @[data] to the buffer.
|
8cccac | 2014-08-28 | Per Hedbor | | *!
|
50c719 | 2014-09-10 | Per Hedbor | | *! This is identical to
|
21893c | 2014-10-19 | Henrik Grubbström (Grubba) | | *! @tt{sprintf("%"+size_size+"H",(string)Stdio.Buffer(data))@} but
|
50c719 | 2014-09-10 | Per Hedbor | | *! significantly faster.
|
8cccac | 2014-08-28 | Per Hedbor | | *!
|
50c719 | 2014-09-10 | Per Hedbor | | *! @[size_size] is the number of bytes used to represent the length of the data.
*! It must be less than Int.NATIVE_MAX.
*!
|
7772e6 | 2014-09-29 | Stephen R. van den Berg | | *! @[offset] is added to the length of the data prior to writing out
*! the length. Typical usage involves adding @[size_size] to account
*! for the room used by the size.
*!
|
50c719 | 2014-09-10 | Per Hedbor | | *! The supported @[data] argument types are
*!
*! @mixed
|
7772e6 | 2014-09-29 | Stephen R. van den Berg | | *! @type int(0..255)
*! An eight bit character.
|
50c719 | 2014-09-10 | Per Hedbor | | *! @type string(0..255)
*! An eight bit string.
*! @type System.Memory
*! A chunk of memory. The whole memory area is added.
|
cb6501 | 2014-10-01 | Martin Nilsson | | *! @type Stdio.Buffer
|
50c719 | 2014-09-10 | Per Hedbor | | *! 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
|
8cccac | 2014-08-28 | Per Hedbor | | */
|
fbc3bf | 2014-09-08 | Per Hedbor | |
|
d7ec8f | 2014-09-30 | Per Hedbor | | /* we can not use the actual type here.
the reason is that this class is loaded before the master is, so
we cannot possibly use things that require the master (such as
resolving things.)
*/
|
7772e6 | 2014-09-29 | Stephen R. van den Berg | | PIKEFUN Buffer add_hstring(
int|string|object|array(int|string|Buffer|array) str,
int size_size, void|int offset )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
50c719 | 2014-09-10 | Per Hedbor | | size_t len = io_svalue_len(io, str);
|
fbc3bf | 2014-09-08 | Per Hedbor | |
|
7772e6 | 2014-09-29 | Stephen R. van den Berg | | if( offset )
len += offset->u.integer;
|
50c719 | 2014-09-10 | Per Hedbor | | if( size_size < (int)sizeof(size_t) &&
|
fbc3bf | 2014-09-08 | Per 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 );
|
50c719 | 2014-09-10 | Per Hedbor | | io_append_svalue( io, str );
|
9fc2ef | 2014-09-08 | Per Hedbor | | pop_n_elems(args);
|
fbc3bf | 2014-09-08 | Per Hedbor | | ref_push_object(io->this);
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | /*! @decl Buffer add_int( int i, int(0..) width )
|
8cccac | 2014-08-28 | Per Hedbor | | *!
*! Adds a generic integer to the buffer as an (width*8)bit
*! network byteorder number.
*!
*! @[width] must be less than Int.NATIVE_MAX.
*!
*/
|
cb6501 | 2014-10-01 | Martin Nilsson | | PIKEFUN Buffer add_int( object|int i, int width )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
fbc3bf | 2014-09-08 | Per Hedbor | | pop_stack(); /* width */
|
f3ed29 | 2014-09-11 | Per Hedbor | | if( TYPEOF(*i) == PIKE_T_INT )
{
io_add_int( THIS, i->u.integer, width );
Pike_sp--;
}
else
{
convert_stack_top_to_bignum();
io_add_bignum( THIS, i->u.object, width );
pop_stack(); /* o. */
}
|
317fc3 | 2014-09-02 | Per Hedbor | | ref_push_object(Pike_fp->current_object);
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | /*! @decl Buffer add_hint( int i, int(0..) size_width )
|
3a3c82 | 2014-09-25 | Per Hedbor | | *!
*! First add the size of the integer when encoded to base 256 as a
*! @[size_width] integer, then add the integer to the buffer, both
*! in network byte order.
*!
*! @[size_width] must be less than Int.NATIVE_MAX.
*!
*/
|
cb6501 | 2014-10-01 | Martin Nilsson | | PIKEFUN Buffer add_hint( object|int i, int len_width )
|
3a3c82 | 2014-09-25 | Per Hedbor | | {
int width;
pop_stack(); /* width */
if( TYPEOF(*i) == PIKE_T_INT )
{
INT_TYPE ui = i->u.integer;
for( width=0; width<SIZEOF_INT_TYPE; width++ )
|
ff1726 | 2015-04-21 | Henrik Grubbström (Grubba) | | if( ui < (((INT_TYPE)1)<<(width*8)) &&
ui >= -(((INT_TYPE)1)<<(width*8-1)) )
break;
|
3a3c82 | 2014-09-25 | Per Hedbor | | io_add_int( THIS, width, len_width );
io_add_int( THIS, i->u.integer, width );
Pike_sp--;
}
else
{
convert_stack_top_to_bignum();
width = (mpz_sizeinbase( (void*)i->u.object->storage, 2)+7)/8;
io_add_int( THIS, width, len_width );
io_add_bignum( THIS, i->u.object, width );
pop_stack(); /* o. */
}
ref_push_object(Pike_fp->current_object);
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | /*! @decl Buffer add_ints( array(int) integers, int(0..255) len )
|
342f56 | 2014-09-02 | Per Hedbor | | *!
*! Add the integers in the specified array, @[len] bytes per int.
|
fbc3bf | 2014-09-08 | Per 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.
|
342f56 | 2014-09-02 | Per Hedbor | | */
|
cb6501 | 2014-10-01 | Martin Nilsson | | PIKEFUN Buffer add_ints( array(int) a, int bpi )
|
342f56 | 2014-09-02 | Per Hedbor | | {
|
fbc3bf | 2014-09-08 | Per Hedbor | | int i,l = a->size;
struct svalue *it = a->item;
unsigned char *ptr;
|
130baa | 2014-10-03 | Per Hedbor | | ptrdiff_t n=0;
|
fbc3bf | 2014-09-08 | Per Hedbor | | ONERROR e;
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
342f56 | 2014-09-02 | Per Hedbor | |
|
fbc3bf | 2014-09-08 | Per Hedbor | | io_unwrite_on_error(io, &e);
|
342f56 | 2014-09-02 | Per Hedbor | |
|
fbc3bf | 2014-09-08 | Per Hedbor | | if( bpi < 0 )
Pike_error("Illegal int width\n");
|
130baa | 2014-10-03 | Per Hedbor | | #if SIZEOF_LONG == 4
if( DO_INT32_MUL_OVERFLOW( l, bpi, &n ) )
|
fbc3bf | 2014-09-08 | Per Hedbor | | #else
|
50c719 | 2014-09-10 | Per Hedbor | | if( DO_INT64_MUL_OVERFLOW( l, bpi, &n ) )
|
fbc3bf | 2014-09-08 | Per Hedbor | | #endif
|
5944b3 | 2014-09-11 | Henrik Grubbström (Grubba) | | Pike_error("Result size exceeds ptrdiff_t size\n");
|
fbc3bf | 2014-09-08 | Per Hedbor | |
io_add_space( io, n, 0 );
switch( bpi )
{
|
50c719 | 2014-09-10 | Per 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:
|
342f56 | 2014-09-02 | Per Hedbor | | #if SIZEOF_INT_TYPE > 4
|
50c719 | 2014-09-10 | Per Hedbor | | case 5:
case 6:
case 7:
|
342f56 | 2014-09-02 | Per Hedbor | | #endif
|
50c719 | 2014-09-10 | Per Hedbor | | for( i=0; i<l; i++ )
|
fbc3bf | 2014-09-08 | Per Hedbor | | io_add_int_uc( io, get_small_int(it+i), bpi );
break;
default:
/* bignums. */
for( i=0; i<l; i++ )
{
|
50c719 | 2014-09-10 | Per 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");
|
fbc3bf | 2014-09-08 | Per Hedbor | | }
}
io_unset_unwrite_on_error( io, &e );
io_trigger_output( io );
|
50c719 | 2014-09-10 | Per Hedbor | | Pike_sp--;
pop_stack();
|
fbc3bf | 2014-09-08 | Per Hedbor | | ref_push_object(io->this);
|
342f56 | 2014-09-02 | Per Hedbor | | }
|
8cccac | 2014-08-28 | Per Hedbor | | /*! @decl protected int `[](int off)
*!
*! Return the character at the specified offset.
*/
|
9629ad | 2014-09-01 | Per Hedbor | | PIKEFUN int(0..255) `[]( int off )
|
8cccac | 2014-08-28 | Per Hedbor | | flags ID_PROTECTED;
{
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
8cccac | 2014-08-28 | Per Hedbor | | if( off < 0 )
off = io_len(io)-off;
if( io_avail( io, off ) )
|
89aecf | 2014-09-12 | Per Hedbor | | Pike_sp[-1].u.integer = io_read_pointer(io)[off];
|
8cccac | 2014-08-28 | Per Hedbor | | else
|
89aecf | 2014-09-12 | Per Hedbor | | Pike_sp[-1].u.integer = -1;
|
8cccac | 2014-08-28 | Per Hedbor | | }
/*! @decl protected int `[]=(int off, int char)
*!
*! Set the character at the specified offset to @[char].
*/
|
9629ad | 2014-09-01 | Per Hedbor | | PIKEFUN int(0..255) `[]=( int off, int val )
|
8cccac | 2014-08-28 | Per Hedbor | | flags ID_PROTECTED;
{
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
89aecf | 2014-09-12 | Per Hedbor | |
|
fbc3bf | 2014-09-08 | Per Hedbor | | io_ensure_malloced( io, 0 );
|
8cccac | 2014-08-28 | Per Hedbor | |
if( off < 0 ) off = io_len(io)-off;
|
89aecf | 2014-09-12 | Per Hedbor | | again:
|
8cccac | 2014-08-28 | Per Hedbor | | if( io_avail( io, off ) )
{
io_read_pointer(io)[off]=(val&0xff);
}
else
{
|
89aecf | 2014-09-12 | Per Hedbor | | /* hm, well. We could extend the buffer. Should we? */
if( io_range_error(io, off ) )
goto again;
Pike_error("Writing outside buffer\n");
|
8cccac | 2014-08-28 | Per Hedbor | | }
}
/*! @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.
*/
|
9629ad | 2014-09-01 | Per Hedbor | | PIKEFUN int(0..) _sizeof()
|
8cccac | 2014-08-28 | Per 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.
*/
|
9629ad | 2014-09-01 | Per Hedbor | | PIKEFUN string(0..255) cast(string to)
|
e82565 | 2014-12-01 | Martin Nilsson | | flags ID_PROTECTED;
|
8cccac | 2014-08-28 | Per 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)));
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | /*! @decl Buffer set_error_mode(int m)
*! @decl Buffer set_error_mode(program m)
|
8cccac | 2014-08-28 | Per Hedbor | | *!
*! Set the error mode of this buffer to @[m].
*!
|
9629ad | 2014-09-01 | Per 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.
|
8cccac | 2014-08-28 | Per 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 );
*!
|
cb6501 | 2014-10-01 | Martin Nilsson | | *! while( Buffer packet = inbuffer->read_hbuffer(2) )
|
8cccac | 2014-08-28 | Per Hedbor | | *! {
*! 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
*! }
*! }
*!
*!
|
cb6501 | 2014-10-01 | Martin Nilsson | | *! void handle_packet( Buffer pack )
|
8cccac | 2014-08-28 | Per Hedbor | | *! {
*! 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
*/
|
cb6501 | 2014-10-01 | Martin Nilsson | | PIKEFUN Buffer set_error_mode( int|program m )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
89aecf | 2014-09-12 | Per 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();
|
fbc3bf | 2014-09-08 | Per Hedbor | | ref_push_object(Pike_fp->current_object);
|
8cccac | 2014-08-28 | Per Hedbor | | }
/*! @decl object lock()
*!
*! Makes this buffer read only until the returned object is released.
*!
*! @note
*! This currently simply returns a 0-length subbuffer.
*/
|
cb6501 | 2014-10-01 | Martin Nilsson | | PIKEFUN Buffer lock()
|
8cccac | 2014-08-28 | Per Hedbor | | {
push_object( io_read_buffer( THIS, 0, 0 ) );
}
|
02cc64 | 2019-09-18 | Henrik Grubbström (Grubba) | | PIKEFUN string(0..255) _sprintf(int o, mapping|void UNUSED)
|
8cccac | 2014-08-28 | Per Hedbor | | flags ID_PROTECTED;
{
|
4a39cb | 2014-11-26 | Henrik Grubbström (Grubba) | | size_t bytes;
|
89aecf | 2014-09-12 | Per Hedbor | | pop_n_elems(args-1);
Pike_sp--;
switch( o )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
89aecf | 2014-09-12 | Per Hedbor | | case 'O':
{
push_text("%O(%d bytes, read=[..%d] data=[%d..%d] free=[%d..%d] %s%s)");
ref_push_program(Pike_fp->current_object->prog);
/* io_len [..offset] [offset..len] [..allocated] */
push_int(io_len(THIS));
push_int(THIS->offset-1);
push_int(THIS->offset);
push_int(THIS->len-1);
push_int(THIS->len);
push_int(THIS->allocated);
push_text( (THIS->str ? "string" : THIS->malloced ? "allocated" : "subbuffer" ) );
if( THIS->locked )
push_text(" (read only)");
else
push_text("");
f_sprintf(10);
}
break;
case 's':
|
4a39cb | 2014-11-26 | Henrik Grubbström (Grubba) | | bytes = io_len(THIS);
push_string( io_read_string(THIS, bytes) );
io_rewind(THIS, bytes);
|
89aecf | 2014-09-12 | Per Hedbor | | break;
case 'q':
push_text("%q");
|
4a39cb | 2014-11-26 | Henrik Grubbström (Grubba) | | bytes = io_len(THIS);
push_string( io_read_string(THIS, bytes) );
io_rewind(THIS, bytes);
|
89aecf | 2014-09-12 | Per Hedbor | | f_sprintf(2);
break;
default:
push_undefined();
|
8cccac | 2014-08-28 | Per Hedbor | | }
}
|
7772e6 | 2014-09-29 | Stephen R. van den Berg | | /*! @decl string(8bit) read_hstring( int(0..) n, void|int offset )
|
8cccac | 2014-08-28 | Per Hedbor | | *!
*! 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.
*!
|
7772e6 | 2014-09-29 | Stephen R. van den Berg | | *! @[offset] is substracted from the specified length prior to reading the
*! string. Typical usage involves substracting @[n] to account
*! for the room used by the size.
*!
|
8cccac | 2014-08-28 | Per Hedbor | | *! If there is not enough data available return 0.
*!
*! Note that pike string can not be longer than 0x7fffffff bytes (~2Gb).
*/
|
7772e6 | 2014-09-29 | Stephen R. van den Berg | | PIKEFUN string(0..255) read_hstring( int bytes, void|int offset )
|
8cccac | 2014-08-28 | Per Hedbor | | {
LONGEST len;
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
8cccac | 2014-08-28 | Per Hedbor | | struct pike_string *s;
|
fbc3bf | 2014-09-08 | Per Hedbor | | ONERROR e;
|
8cccac | 2014-08-28 | Per Hedbor | |
|
ebd1d4 | 2014-09-14 | Per Hedbor | | io_rewind_on_error( io, &e );
len = io_read_number( io, bytes );
|
ebd004 | 2014-09-05 | Henrik Grubbström (Grubba) | |
|
7772e6 | 2014-09-29 | Stephen R. van den Berg | | if (offset)
len -= offset->u.integer;
|
ebd1d4 | 2014-09-14 | Per Hedbor | | if (len < 0) {
/* io_avail() in io_read_number() failed. */
CALL_AND_UNSET_ONERROR(e);
Pike_sp[-1].u.integer = 0;
|
ebd004 | 2014-09-05 | Henrik Grubbström (Grubba) | | return;
}
|
ebd1d4 | 2014-09-14 | Per Hedbor | | /* NB: We assume that io_avail() in io_read_string() doesn't throw. */
|
fbc3bf | 2014-09-08 | Per Hedbor | | s = io_read_string( io, len );
|
ebd004 | 2014-09-05 | Henrik Grubbström (Grubba) | |
if( s ) {
|
fbc3bf | 2014-09-08 | Per Hedbor | | io_unset_rewind_on_error( io, &e );
|
ebd1d4 | 2014-09-14 | Per Hedbor | | Pike_sp--;
|
8cccac | 2014-08-28 | Per Hedbor | | push_string(s);
|
ebd004 | 2014-09-05 | Henrik Grubbström (Grubba) | | } else {
|
ebd1d4 | 2014-09-14 | Per Hedbor | | CALL_AND_UNSET_ONERROR(e);
Pike_sp[-1].u.integer = 0;
|
ebd004 | 2014-09-05 | Henrik Grubbström (Grubba) | | }
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
8a3d42 | 2014-09-14 | Stephen R. van den Berg | | /*! @decl string(8bit) read_cstring( )
*!
*! 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).
|
1997db | 2016-10-10 | Henrik Grubbström (Grubba) | | *!
*! @seealso
*! @[_search()]
|
8a3d42 | 2014-09-14 | Stephen R. van den Berg | | */
|
0da32f | 2018-05-17 | Stephen R. van den Berg | | PIKEFUN string(0..255) read_cstring()
|
8a3d42 | 2014-09-14 | Stephen R. van den Berg | | {
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
8a3d42 | 2014-09-14 | Stephen R. van den Berg | |
|
0da32f | 2018-05-17 | Stephen R. van den Berg | | do
if ( LIKELY(io_len(THIS)) )
|
bac539 | 2014-09-25 | Per Hedbor | | {
|
7bd2c8 | 2018-05-22 | Henrik Grubbström (Grubba) | | const unsigned char * start = io_read_pointer(io);
const unsigned char * end = memchr(start, 0, io_len(io));
|
0da32f | 2018-05-17 | Stephen R. van den Berg | | if ( LIKELY(end) )
{
push_string(io_read_string(io, end - start));
io_read_byte_uc(io); /* consume the terminating \0 byte */
return;
}
|
bac539 | 2014-09-25 | Per Hedbor | | }
|
0da32f | 2018-05-17 | Stephen R. van den Berg | | while ( UNLIKELY(io_range_error(THIS, 0)) );
|
8a3d42 | 2014-09-14 | Stephen R. van den Berg | |
|
0da32f | 2018-05-17 | Stephen R. van den Berg | | push_undefined();
|
8a3d42 | 2014-09-14 | Stephen R. van den Berg | | }
|
1997db | 2016-10-10 | Henrik Grubbström (Grubba) | | /*! @decl protected int(-1..) _search(int(8bit) character, int|void start)
*!
*! Search forward from the indicated @[start] position for the specified
*! @[character].
*!
*! @param character
*! Character to search for.
*!
*! @param start
*! Start position relative to the current read position of the buffer.
*!
*! Negative @[start] values are supported and indicate positions
*! prior to the current read position.
*!
*! @returns
*! Returns the first found position of @[character] relative to the
*! current read position of the buffer on success, and @[UNDEFINED]
*! on not found. The read position is not advanced.
*!
*! @seealso
*! @[read_cstring()], @[search()], @[lfun::_search()]
*/
PIKEFUN int _search(int(8bit) character, int|void start)
flags ID_PROTECTED;
{
Buffer *io = THIS;
unsigned char *buf = io_read_pointer(io);
unsigned char *buf_start = buf;
unsigned char *buf_end = buf + io_len(io);
if (start) {
INT_TYPE bytes = start->u.integer;
buf_start += bytes;
if (bytes >= 0) {
if (((size_t)bytes) >= io_len(io)) {
push_int(-1);
return;
}
} else if (((size_t)(-bytes)) > io->offset) {
bytes = -(ptrdiff_t)io->offset;
}
buf += bytes;
}
while (buf < buf_end) {
if (UNLIKELY(*buf == character)) {
push_int64(buf - io_read_pointer(io));
return;
}
buf++;
}
push_int(-1);
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | /*! @decl Buffer read_hbuffer( int n )
*! @decl Buffer read_hbuffer( int n, bool copy )
|
8cccac | 2014-08-28 | Per Hedbor | | *!
|
cb6501 | 2014-10-01 | Martin Nilsson | | *! Same as @[read_hstring], but returns the result as an Buffer.
|
8cccac | 2014-08-28 | Per Hedbor | | *!
*! 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.
*/
|
cb6501 | 2014-10-01 | Martin Nilsson | | PIKEFUN Buffer read_hbuffer( int bytes, int|void copy )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
ebd004 | 2014-09-05 | Henrik Grubbström (Grubba) | | LONGEST len;
|
8cccac | 2014-08-28 | Per Hedbor | | int do_copy = 0;
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
fbc3bf | 2014-09-08 | Per Hedbor | | ONERROR e;
io_rewind_on_error( io, &e );
|
ebd004 | 2014-09-05 | Henrik Grubbström (Grubba) | |
|
8cccac | 2014-08-28 | Per Hedbor | | if( copy ) do_copy = copy->u.integer;
|
7c8944 | 2014-09-11 | Per Hedbor | | Pike_sp-=args;
|
8cccac | 2014-08-28 | Per Hedbor | |
|
fbc3bf | 2014-09-08 | Per 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 );
|
ebd004 | 2014-09-05 | Henrik Grubbström (Grubba) | | return;
}
|
fbc3bf | 2014-09-08 | Per Hedbor | | CALL_AND_UNSET_ONERROR(e);
push_int(0);
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
cb6501 | 2014-10-01 | Martin Nilsson | | /*! @decl Buffer read_buffer( int n )
*! @decl Buffer read_buffer( int n, bool copy )
|
8cccac | 2014-08-28 | Per Hedbor | | *!
|
cb6501 | 2014-10-01 | Martin Nilsson | | *! Same as @[read], but returns the result as an Buffer.
|
8cccac | 2014-08-28 | Per Hedbor | | *!
*! 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.
*/
|
cb6501 | 2014-10-01 | Martin Nilsson | | PIKEFUN Buffer read_buffer( int bytes, int|void copy )
|
8cccac | 2014-08-28 | Per Hedbor | | {
int do_copy = 0;
struct object *o;
if( copy )
do_copy = copy->u.integer;
|
7c8944 | 2014-09-11 | Per Hedbor | | Pike_sp-=args;
|
8cccac | 2014-08-28 | Per Hedbor | | if( (o = io_read_buffer( THIS, bytes, do_copy )) )
push_object(o);
else
push_int(0);
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | /*! @decl Buffer sprintf(strict_sprintf_format format, sprintf_args ... args)
|
8cccac | 2014-08-28 | Per 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.
*/
|
53ddce | 2014-10-12 | Henrik Grubbström (Grubba) | | PIKEFUN Buffer sprintf(mixed ... ignored)
|
8cccac | 2014-08-28 | Per Hedbor | | rawtype tFuncV(tAttr("strict_sprintf_format", tOr(tStr, tObj)),
|
53ddce | 2014-10-12 | Henrik Grubbström (Grubba) | | tAttr("sprintf_args", tMix), tObjIs_BUFFER);
|
8cccac | 2014-08-28 | Per Hedbor | | {
ONERROR _e;
struct string_builder tmp;
init_string_builder(&tmp,0);
SET_ONERROR(_e, free_string_builder, &tmp);
low_f_sprintf(args, 0, &tmp );
if( tmp.s->size_shift )
|
cb6501 | 2014-10-01 | Martin Nilsson | | Pike_error("Buffer only handles 8bit data\n");
|
7c3477 | 2014-09-11 | Per Hedbor | | io_append( THIS, tmp.s->str, tmp.s->len );
|
8cccac | 2014-08-28 | Per Hedbor | | pop_n_elems(args);
CALL_AND_UNSET_ONERROR(_e);
|
fbc3bf | 2014-09-08 | Per Hedbor | | ref_push_object(Pike_fp->current_object);
|
8cccac | 2014-08-28 | Per 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;
|
317fc3 | 2014-09-02 | Per Hedbor | | retry:
|
8cccac | 2014-08-28 | Per 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 )
{
|
317fc3 | 2014-09-02 | Per Hedbor | | if( io_range_error(THIS,0) )
goto retry;
|
8cccac | 2014-08-28 | Per Hedbor | | pop_n_elems(Pike_sp-start);
push_int(0);
}
else
{
io_consume( THIS, num_used );
f_aggregate(Pike_sp-start);
}
}
|
8f0820 | 2014-08-28 | Per Hedbor | | /*! @decl mixed read_json(int|void require_whitespace_separator)
*!
*! Read a single JSON expression from the buffer and return it.
|
317fc3 | 2014-09-02 | Per Hedbor | | *!
|
8f0820 | 2014-08-28 | Per 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)
{
|
aa94b0 | 2017-06-29 | Arne Goedeke | | INT_TYPE whites = 0;
|
5ca7e2 | 2017-06-29 | Arne Goedeke | | ptrdiff_t stop;
|
8f0820 | 2014-08-28 | Per Hedbor | | static ptrdiff_t(*parse_json_pcharp)(PCHARP,size_t,int,char**);
char *err = NULL;
if( require_whitespace )
whites = require_whitespace->u.integer;
|
89aecf | 2014-09-12 | Per Hedbor | | Pike_sp-=args;
|
8f0820 | 2014-08-28 | Per Hedbor | | if( !parse_json_pcharp )
parse_json_pcharp = PIKE_MODULE_IMPORT(Standards.JSON, parse_json_pcharp );
|
317fc3 | 2014-09-02 | Per Hedbor | | retry:
|
8f0820 | 2014-08-28 | Per 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)))
{
|
317fc3 | 2014-09-02 | Per Hedbor | | if( io_range_error(THIS,0) )
goto retry;
|
8f0820 | 2014-08-28 | Per 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) )
{
|
317fc3 | 2014-09-02 | Per Hedbor | | if( io_range_error(THIS,0) )
goto retry;
|
8f0820 | 2014-08-28 | Per 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 );
}
}
}
|
8cccac | 2014-08-28 | Per 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.
|
89aecf | 2014-09-12 | Per Hedbor | | *! buffer->match("%*[ \t\r\n]%[^ \t\r\n]");
|
8cccac | 2014-08-28 | Per Hedbor | | *! @endcode
*/
|
9629ad | 2014-09-01 | Per Hedbor | | PIKEFUN string(0..255)|int|float|array match( string format )
|
8cccac | 2014-08-28 | Per Hedbor | | {
INT32 i;
ptrdiff_t num_used;
struct svalue *start = Pike_sp;
|
317fc3 | 2014-09-02 | Per Hedbor | | retry:
|
8cccac | 2014-08-28 | Per Hedbor | | i = low_sscanf_pcharp(
MKPCHARP(io_read_pointer(THIS), 0), io_len(THIS),
MKPCHARP(format->str,format->size_shift), format->len,
|
fbc3bf | 2014-09-08 | Per Hedbor | | &num_used,
|
8cccac | 2014-08-28 | Per Hedbor | | 0);
if( !num_used )
{
|
317fc3 | 2014-09-02 | Per Hedbor | | if( io_range_error(THIS,0) )
goto retry;
|
8cccac | 2014-08-28 | Per Hedbor | | pop_n_elems(Pike_sp-start);
push_int(0);
}
else
{
io_consume( THIS, num_used );
|
89aecf | 2014-09-12 | Per Hedbor | | if( Pike_sp-start > 1 )
|
8cccac | 2014-08-28 | Per Hedbor | | f_add(Pike_sp-start);
}
}
/*! @decl void clear()
*!
*! Clear the buffer.
*/
PIKEFUN void clear( )
{
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
8cccac | 2014-08-28 | Per Hedbor | | io->offset = io->len = 0;
}
|
2c4241 | 2015-07-13 | Per Hedbor | | /*! @decl void set_max_waste(float factor)
*!
*! Configure how much free space should be allowed, at most, as a
*! 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 );
|
9db222 | 2017-07-30 | Arne Goedeke | | io_trim_waste( io );
|
2c4241 | 2015-07-13 | Per Hedbor | | }
|
8cccac | 2014-08-28 | Per Hedbor | | /*! @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( )
{
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
3c0dee | 2015-05-15 | Tobias S. Josefowitz | | void *new_ptr;
|
8cccac | 2014-08-28 | Per Hedbor | | io_add_space( io, 0, 1 );
|
2c4241 | 2015-07-13 | Per Hedbor | | io_trim(io);
|
8cccac | 2014-08-28 | Per Hedbor | | }
/*! @decl int(0..)|int(-1..-1) consume( int(0..) n )
*!
*! Discard the first @[n] bytes from the buffer
|
fbc3bf | 2014-09-08 | Per Hedbor | | *!
*! Returns -1 on error and the amount of space still left otherwise.
|
8cccac | 2014-08-28 | Per Hedbor | | */
PIKEFUN int(-1..) consume( int n )
{
|
89aecf | 2014-09-12 | Per Hedbor | | Pike_sp--;
|
ebd1d4 | 2014-09-14 | Per Hedbor | | if( !io_avail( THIS, n ) )
|
8cccac | 2014-08-28 | Per Hedbor | | push_int(-1);
else
push_int64( io_consume( THIS, n ) );
}
|
bdcb18 | 2015-11-21 | Arne Goedeke | | /*! @decl int(0..)|int(-1..-1) truncate( int(0..) n )
*!
*! Truncates the buffer to a length of @[n] bytes.
*!
*! Returns -1 on error and the number of bytes removed otherwise.
*/
PIKEFUN int(-1..) truncate( int(0..) n )
{
Buffer *io = THIS;
ptrdiff_t diff = io_len(io) - n;
Pike_sp--;
if( diff < 0 || io_len(io) < (size_t)diff )
push_int(-1);
else {
io->len -= diff;
push_int64( diff );
}
}
|
8cccac | 2014-08-28 | Per Hedbor | |
/*! @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.
*!
|
b06488 | 2014-09-11 | Stephen R. van den Berg | | *! You can call @[unread(0)] to see how much.
|
8cccac | 2014-08-28 | Per Hedbor | | */
|
9629ad | 2014-09-01 | Per Hedbor | | PIKEFUN int(-1..) unread( int bytes )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
89aecf | 2014-09-12 | Per Hedbor | | Pike_sp--;
|
ebd1d4 | 2014-09-14 | Per Hedbor | | push_int64( io_rewind( THIS, bytes ) );
|
8cccac | 2014-08-28 | Per Hedbor | | }
/*! @decl string(8bit) read( int n )
*!
|
d504d4 | 2018-10-09 | Jonas Walldén | | *! Read @[n] bytes of data from the buffer.
|
8cccac | 2014-08-28 | Per Hedbor | | *!
*! If there is not enough data available this returns 0.
|
f744bf | 2014-09-15 | Henrik Grubbström (Grubba) | | *!
*! @seealso
*! @[try_read()]
|
8cccac | 2014-08-28 | Per Hedbor | | */
|
9629ad | 2014-09-01 | Per Hedbor | | PIKEFUN string(0..255) read( int bytes )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
317fc3 | 2014-09-02 | Per Hedbor | | struct pike_string *s;
|
89aecf | 2014-09-12 | Per Hedbor | | Pike_sp--;
|
317fc3 | 2014-09-02 | Per Hedbor | | s = io_read_string(THIS, bytes );
|
8cccac | 2014-08-28 | Per Hedbor | | if( s )
|
89aecf | 2014-09-12 | Per Hedbor | | push_string( s );
else
push_undefined();
|
8cccac | 2014-08-28 | Per 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.
|
f744bf | 2014-09-15 | Henrik Grubbström (Grubba) | | *!
*! @seealso
*! @[try_read()]
|
8cccac | 2014-08-28 | Per Hedbor | | */
PIKEFUN string(0..255) read()
{
|
8cfdd8 | 2014-09-15 | Per Hedbor | | push_string( io_read_string(THIS, io_len(THIS)) );
|
f744bf | 2014-09-15 | Henrik Grubbström (Grubba) | | }
/*! @decl string(8bit) try_read(int len)
*!
*! Attempt to read some data from the buffer.
*!
*! @param len
*! Read at most @[len] bytes from the buffer.
*!
*! @returns
*! If the buffer contains less than @[len] bytes
*! of data, the entire buffer contents are returned.
*! Otherwise the first @[len] bytes are returned.
*!
*! @seealso
*! @[read()]
*/
PIKEFUN string(0..255) try_read( int bytes )
{
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *this = THIS;
|
f744bf | 2014-09-15 | Henrik Grubbström (Grubba) | | struct pike_string *s;
Pike_sp--;
|
401513 | 2014-09-15 | Per Hedbor | | /* Hm. signed/unsigned comparisons abound. */
|
e555b0 | 2014-09-15 | Per Hedbor | | if( bytes > 0 && (size_t)bytes > io_len(this) )
|
401513 | 2014-09-15 | Per Hedbor | | bytes = io_len(this);
push_string( io_read_string(this, bytes ) );
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
c5e3e5 | 2014-09-10 | Per Hedbor | | /*! @decl int(8bit) read_int8()
*/
PIKEFUN int(8bit) read_int8( )
{
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
c5e3e5 | 2014-09-10 | Per Hedbor | | 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( )
{
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
c5e3e5 | 2014-09-10 | Per Hedbor | | 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( )
{
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
c5e3e5 | 2014-09-10 | Per Hedbor | | if( LIKELY(io_avail( io, 3 )) )
push_int( io_read_number_uc(io,3) );
else
push_int(-1);
}
|
045518 | 2014-09-11 | Arne Goedeke | | /*! @decl int(32bit) read_int32()
|
c5e3e5 | 2014-09-10 | Per Hedbor | | */
|
045518 | 2014-09-11 | Arne Goedeke | | PIKEFUN int(0..4294967295) read_int32( )
|
c5e3e5 | 2014-09-10 | Per Hedbor | | {
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
c5e3e5 | 2014-09-10 | Per Hedbor | | if( LIKELY(io_avail( io, 4 )) )
|
130baa | 2014-10-03 | Per Hedbor | | {
|
c5e3e5 | 2014-09-10 | Per Hedbor | | push_int( io_read_number_uc(io,4) );
|
130baa | 2014-10-03 | Per Hedbor | | #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) );
}
#endif
}
|
c5e3e5 | 2014-09-10 | Per Hedbor | | else
push_int(-1);
}
|
74e52c | 2014-08-28 | Per Hedbor | | /*! @decl int read_int( int n )
|
8cccac | 2014-08-28 | Per Hedbor | | *!
|
fbc3bf | 2014-09-08 | Per Hedbor | | *! Read a network byte order unsigned number of size n*8 bits, then
|
8cccac | 2014-08-28 | Per Hedbor | | *! return it.
*!
*! Will return -1 if there is not enough buffer space available
*! unless error mode is set to throw errors.
*/
|
9629ad | 2014-09-01 | Per Hedbor | | PIKEFUN int(0..) read_int( int len )
|
8cccac | 2014-08-28 | Per Hedbor | | {
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
8cccac | 2014-08-28 | Per Hedbor | | struct object *o;
|
89aecf | 2014-09-12 | Per Hedbor | | Pike_sp--;
|
8cccac | 2014-08-28 | Per Hedbor | |
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);
}
|
3a3c82 | 2014-09-25 | Per Hedbor | | /*! @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 )
{
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
3a3c82 | 2014-09-25 | Per Hedbor | | ONERROR e;
INT_TYPE len;
struct object *o;
io_rewind_on_error( io, &e );
len = io_read_number( io, size_len );
if( len >= 0 )
{
if( len < SIZEOF_INT_TYPE )
{
if( (Pike_sp[-1].u.integer = io_read_number( io, len )) == -1 )
goto neg_one;
}
else if( (o = io_read_bignum( io, len )) )
{
Pike_sp--;
push_object(o);
reduce_stack_top_bignum();
}
else
goto neg_one;
io_unset_rewind_on_error( io, &e );
return;
}
neg_one:
Pike_sp[-1].u.integer = -1;
CALL_AND_UNSET_ONERROR(e);
}
|
fbc3bf | 2014-09-08 | Per 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 )
{
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *io = THIS;
|
fbc3bf | 2014-09-08 | Per Hedbor | | INT_TYPE i;
struct object *o;
struct array *a;
|
89aecf | 2014-09-12 | Per Hedbor | | Pike_sp-=2;
|
fbc3bf | 2014-09-08 | Per Hedbor | |
|
ebd1d4 | 2014-09-14 | Per Hedbor | | if( !io_avail_mul( io, num, len ) )
|
fbc3bf | 2014-09-08 | Per Hedbor | | {
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);
}
|
6d4796 | 2014-09-01 | Per Hedbor | | /*! @decl string _encode()
*! @decl void _decode(string x)
*!
|
cb6501 | 2014-10-01 | Martin Nilsson | | *! Encode and decode Stdio.Buffer objects.
|
6d4796 | 2014-09-01 | Per Hedbor | | *! Only the buffer data is kept, no other state is saved.
*/
PIKEFUN string _encode()
{
|
fbc3bf | 2014-09-08 | Per Hedbor | | push_string(io_read_string(THIS, io_len(THIS)));
|
6d4796 | 2014-09-01 | Per Hedbor | | }
PIKEFUN void _decode(string(0..255) x)
{
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *this = THIS;
|
6d4796 | 2014-09-01 | Per Hedbor | | 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;
|
929b28 | 2014-09-18 | Henrik Grubbström (Grubba) | | add_ref(x);
|
6d4796 | 2014-09-01 | Per Hedbor | | }
|
8b141e | 2014-09-01 | Per Hedbor | |
/*! @decl void read_only()
|
8cccac | 2014-08-28 | Per Hedbor | | *!
|
8b141e | 2014-09-01 | Per Hedbor | | *! Make the buffer permanently read only.
*! @note
*! You can use lock() to do this temporarily.
*/
PIKEFUN void read_only()
{
io_lock( THIS );
}
|
aee764 | 2014-09-25 | Per Hedbor | |
|
cb6501 | 2014-10-01 | Martin Nilsson | | static struct object* io_create_rewind_key( Buffer *io, int how );
|
aee764 | 2014-09-25 | Per Hedbor | |
|
bac539 | 2014-09-25 | Per Hedbor | | /*! @decl RewindKey rewind_on_error()
*! @decl RewindKey rewind_key()
|
aee764 | 2014-09-25 | Per Hedbor | | *!
|
bac539 | 2014-09-25 | Per Hedbor | | *! These functions are very similar. The @[rewind_on_error] edition
*! 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.
|
aee764 | 2014-09-25 | Per Hedbor | | *!
|
bac539 | 2014-09-25 | Per Hedbor | | *! This will happen if you throw an error @i{or@} otherwise let the
|
aee764 | 2014-09-25 | Per Hedbor | | *! object fall out of scope.
*!
|
bac539 | 2014-09-25 | Per Hedbor | | *! Use @[destruct(RewindKey)] or @[RewindKey.release] to stop the
*! buffer from being rewound.
*!
*! The second version (@[rewind_key]) requires you to explicitly
*! call @[RewindKey.rewind] to do the rewind.
*!
|
aee764 | 2014-09-25 | Per Hedbor | | *! 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)
*!
|
bac539 | 2014-09-25 | Per Hedbor | | *! You can call @[RewindKey.update] in the generated object to
*! change where it will be rewound to.
|
aee764 | 2014-09-25 | Per Hedbor | | *!
|
bac539 | 2014-09-25 | Per Hedbor | | *! The typical use-case of this functionality is when parsing a
|
21893c | 2014-10-19 | Henrik Grubbström (Grubba) | | *! packet protocol with variable length packets where the length is
|
bac539 | 2014-09-25 | Per Hedbor | | *! not immediately known. It saves you from keeping track of how
*! much to rewind if you had not actually gotten the whole packet
*! yet.
|
aee764 | 2014-09-25 | Per Hedbor | | *!
*! @example
*! @code
|
cb6501 | 2014-10-01 | Martin Nilsson | | *! void parse_packet( Stdio.Buffer b )
|
aee764 | 2014-09-25 | Per Hedbor | | *! {
|
cb6501 | 2014-10-01 | Martin Nilsson | | *! Stdio.Buffer.RewindKey rewind = b->rewind_on_error();
|
aee764 | 2014-09-25 | Per Hedbor | | *! b->set_error_mode(1);
*!
*! switch( b->read_int8() ) // packet type
*! {
*! case DATA:
*! int channel = b->read_int8();
|
cb6501 | 2014-10-01 | Martin Nilsson | | *! Stdio.Buffer data = b->read_hbuffer( 4 );
|
aee764 | 2014-09-25 | Per Hedbor | | *! // we have read the whole packet, so no longer rewind on error.
*! rewind->release();
|
21893c | 2014-10-19 | Henrik Grubbström (Grubba) | | *! return handle_data_packet( channel, data );
|
aee764 | 2014-09-25 | Per Hedbor | | *! }
*! }
*! @endcode
|
bac539 | 2014-09-25 | Per Hedbor | | *! @note
*! Just calling @[rewind_on_error] without assigning the return
*! value to something will not do anything. You need to keep the
*! object around while the rewind-to position is still valid.
*!
*! Keeping the object around forbids the buffer from moving data
*! inside itself, this means that it can only grow. So do not keep
*! the rewind key when it is not needed.
|
aee764 | 2014-09-25 | Per Hedbor | | */
|
3aa13d | 2014-10-20 | Per Hedbor | | PIKEFUN object(Buffer.RewindKey) rewind_on_error()
|
aee764 | 2014-09-25 | Per Hedbor | | {
|
bac539 | 2014-09-25 | Per Hedbor | | push_object( io_create_rewind_key( THIS, 1 ) );
}
|
3aa13d | 2014-10-20 | Per Hedbor | | PIKEFUN object(Buffer.RewindKey) rewind_key()
|
bac539 | 2014-09-25 | Per Hedbor | | {
push_object( io_create_rewind_key( THIS, 0 ) );
|
aee764 | 2014-09-25 | Per Hedbor | | }
|
8b141e | 2014-09-01 | Per Hedbor | | /*! @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
|
317fc3 | 2014-09-02 | Per Hedbor | | *! size, or if no argument is given, 226 bytes.
|
8b141e | 2014-09-01 | Per Hedbor | | *!
*! If @[contents] are specified a new buffer with the contents of
*! the given string/System.Memory or String.Buffer will be created.
|
8cccac | 2014-08-28 | Per Hedbor | | *!
*! @note
|
8b141e | 2014-09-01 | Per Hedbor | | *! In the @[String.Buffer] case the data has to be copied unless
*! there is only one reference to the String.Buffer object, since
|
cb6501 | 2014-10-01 | Martin Nilsson | | *! modifications of the String.Buffer would cause the Buffer to
|
8b141e | 2014-09-01 | Per Hedbor | | *! 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
|
8cccac | 2014-08-28 | Per Hedbor | | *! string.
|
8b141e | 2014-09-01 | Per 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.
|
8cccac | 2014-08-28 | Per Hedbor | | */
|
f3ed29 | 2014-09-11 | Per Hedbor | | PIKEFUN void create( int|void|string|object|array x )
|
8cccac | 2014-08-28 | Per Hedbor | | flags ID_PROTECTED;
{
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *this = THIS;
|
8cccac | 2014-08-28 | Per Hedbor | | if( this->buffer )
Pike_error("Can not initialize twice.\n");
|
f3ed29 | 2014-09-11 | Per Hedbor | | 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 )
|
fbc3bf | 2014-09-08 | Per Hedbor | | this->buffer = xalloc(1);
|
f3ed29 | 2014-09-11 | Per Hedbor | | else
|
fbc3bf | 2014-09-08 | Per Hedbor | | this->buffer = xalloc(len);
|
130c3d | 2014-10-17 | Henrik Grubbström (Grubba) | | this->allocated = MAXIMUM(len,1);
|
f3ed29 | 2014-09-11 | Per Hedbor | | this->malloced = 1;
}
else
io_append_svalue( THIS, x );
|
8cccac | 2014-08-28 | Per Hedbor | | }
INIT {
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *this = THIS;
memset( this, 0, sizeof(Buffer));
|
2c4241 | 2015-07-13 | Per Hedbor | | this->max_waste = 0.615;
|
317fc3 | 2014-09-02 | Per Hedbor | | this->this = Pike_fp->current_object;
|
8cccac | 2014-08-28 | Per Hedbor | | }
EXIT {
|
cb6501 | 2014-10-01 | Martin Nilsson | | Buffer *this = THIS;
|
50c719 | 2014-09-10 | Per Hedbor | | io_unlink_external_storage( this );
|
9629ad | 2014-09-01 | Per Hedbor | | if( this->error_mode )
free_program( this->error_mode );
|
8cccac | 2014-08-28 | Per Hedbor | | if( this->malloced )
free( this->buffer );
}
|
aee764 | 2014-09-25 | Per Hedbor | |
|
bac539 | 2014-09-25 | Per Hedbor | | /*! @class RewindKey
|
aee764 | 2014-09-25 | Per Hedbor | | *!
|
cb6501 | 2014-10-01 | Martin Nilsson | | *! The return value of @[Buffer.rewind_on_error()] and
*! @[Buffer.rewind_key()]
|
aee764 | 2014-09-25 | Per Hedbor | | *!
|
bac539 | 2014-09-25 | Per Hedbor | | *! This object will cause the buffer to unwind to the position it was
*! at when the object was created either when it is released (when it
*! falls out of scope, explicit destruct does not count) or when
*! @[rewind] is called, depending on which function was used to
*! create it.
|
aee764 | 2014-09-25 | Per Hedbor | | */
|
bac539 | 2014-09-25 | Per Hedbor | | PIKECLASS RewindKey
|
aee764 | 2014-09-25 | Per Hedbor | | flags PROGRAM_DESTRUCT_IMMEDIATE;
{
|
cb6501 | 2014-10-01 | Martin Nilsson | | CVAR Buffer *io;
|
aee764 | 2014-09-25 | Per Hedbor | | CVAR struct object *obj;
CVAR size_t rewind_to;
|
bac539 | 2014-09-25 | Per Hedbor | | CVAR int auto_mode;
|
aee764 | 2014-09-25 | Per Hedbor | |
/*! @decl void release()
|
bac539 | 2014-09-25 | Per Hedbor | | *! Do not rewind if the object is released.
*! @note
*! This is equivalent to calling destruct() on the object
|
aee764 | 2014-09-25 | Per Hedbor | | */
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 )
|
70f4e2 | 2020-03-09 | Henrik Grubbström (Grubba) | | flags ID_PROTECTED;
|
aee764 | 2014-09-25 | Per Hedbor | | {
|
bac539 | 2014-09-25 | Per Hedbor | | if( reason > 1 && THIS->auto_mode ) /* no refs or gc */
|
aee764 | 2014-09-25 | Per Hedbor | | {
if( THIS->io && THIS->obj->prog )
THIS->io->offset = THIS->rewind_to;
}
}
|
a4a648 | 2014-09-25 | Tobias S. Josefowitz | | /*! @decl void rewind()
*! Rewinds the buffer explicitly.
*! @note
|
bac539 | 2014-09-25 | Per Hedbor | | *! Destructs this @[RewindKey]
|
a4a648 | 2014-09-25 | Tobias S. Josefowitz | | */
PIKEFUN void rewind() {
|
bac539 | 2014-09-25 | Per Hedbor | | THIS->auto_mode = 1;
|
a4a648 | 2014-09-25 | Tobias S. Josefowitz | | destruct_object(Pike_fp->current_object, DESTRUCT_GC);
}
|
aee764 | 2014-09-25 | Per Hedbor | | PIKEFUN void create()
|
70f4e2 | 2020-03-09 | Henrik Grubbström (Grubba) | | flags ID_PROTECTED;
|
aee764 | 2014-09-25 | Per Hedbor | | {
|
cc510e | 2014-10-05 | Henrik Grubbström (Grubba) | | /* FIXME: The following zeroing isn't safe! */
|
aee764 | 2014-09-25 | Per Hedbor | | THIS->obj = 0;
THIS->io = 0;
Pike_error("Not supported\n");
}
}
}
|
cb6501 | 2014-10-01 | Martin Nilsson | | static struct object* io_create_rewind_key( Buffer *io, int auto_mode )
|
aee764 | 2014-09-25 | Per Hedbor | | {
|
cb6501 | 2014-10-01 | Martin Nilsson | | struct object *o = fast_clone_object( Buffer_RewindKey_program );
struct Buffer_RewindKey_struct *s = (void*)o->storage;
|
aee764 | 2014-09-25 | Per Hedbor | | add_ref(io->this);
s->obj = io->this;
s->rewind_to = io->offset;
s->io = io;
|
bac539 | 2014-09-25 | Per Hedbor | | s->auto_mode = auto_mode;
|
aee764 | 2014-09-25 | Per Hedbor | | io->locked_move++;
return o;
|
8cccac | 2014-08-28 | Per Hedbor | | }
|
10150d | 2014-09-01 | Per Hedbor | |
|
aee764 | 2014-09-25 | Per Hedbor | | /*! @endclass
|
bac539 | 2014-09-25 | Per Hedbor | | * RewindKey
|
aee764 | 2014-09-25 | Per Hedbor | | */
/*! @endclass
|
cb6501 | 2014-10-01 | Martin Nilsson | | * Buffer
|
aee764 | 2014-09-25 | Per Hedbor | | */
/*! @endmodule
* Stdio
*/
|
8cccac | 2014-08-28 | Per Hedbor | | void init_stdio_buffer(void)
{
INIT
|
10150d | 2014-09-01 | Per 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();
|
8cccac | 2014-08-28 | Per Hedbor | | }
void exit_stdio_buffer(void)
{
|
10150d | 2014-09-01 | Per Hedbor | | free_program( buffer_error_program );
|
8cccac | 2014-08-28 | Per Hedbor | | EXIT
}
|
aee764 | 2014-09-25 | Per Hedbor | |
|