pike.git
/
src
/
builtin.cmod
version
»
Context lines:
10
20
40
80
file
none
3
pike.git/src/builtin.cmod:2900:
*! @[catch()], @[throw()] */ PMOD_EXPORT PIKEFUN array(mixed) backtrace() efun; optflags OPT_EXTERNAL_DEPEND; { low_backtrace(& Pike_interpreter); }
-
/*! @module String
-
*/
-
-
#define PROG_BUFFER_ID PROG_STRING_BUFFER_ID
-
-
/*! @class Buffer
-
*! A buffer, used for building strings. It's
-
*! conceptually similar to a string, but you can only @[add]
-
*! strings to it, and you can only @[get] the value from it once.
-
*!
-
*! There is a reason for those seemingly rather odd limitations,
-
*! it makes it possible to do some optimizations that really speed
-
*! things up.
-
*!
-
*! You do not need to use this class unless you add very many
-
*! strings together, or very large strings.
-
*!
-
*! @example
-
*! For the fastest possible operation, write your code like this:
-
*!
-
*! @code
-
*! String.Buffer b = String.Buffer( );
-
*!
-
*! function add = b->add;
-
*!
-
*! .. call add several times in code ...
-
*!
-
*! string result = b->get(); // also clears the buffer
-
*! @endcode
-
*/
-
PIKECLASS Buffer
-
{
-
CVAR struct string_builder str;
-
CVAR int initial;
-
-
PIKEFUN int _size_object()
-
{
-
if( THIS->str.s )
-
RETURN THIS->str.malloced;
-
RETURN 0;
-
}
-
-
void f_Buffer_get_copy( INT32 args );
-
void f_Buffer_get( INT32 args );
-
void f_Buffer_add( INT32 args );
-
-
/*! @decl void create(int initial_size)
-
*!
-
*! Initializes a new buffer.
-
*!
-
*! If no @[initial_size] is specified, 256 is used. If you
-
*! know approximately how big the buffer will be, you can optimize
-
*! the operation of @[add()] (slightly) by passing the size to this
-
*! function.
-
*/
-
PIKEFUN void create( int|void size )
-
{
-
struct Buffer_struct *str = THIS;
-
if( size )
-
str->initial = MAXIMUM( size->u.integer, 512 );
-
else
-
str->initial = 256;
-
pop_n_elems(args);
-
}
-
-
/*! @decl string _sprintf( int flag, mapping flags )
-
*! It is possible to @[sprintf] a String.Buffer object
-
*! as @tt{%s@} just as if it was a string.
-
*/
-
PIKEFUN string _sprintf( int flag, mapping flags )
-
{
-
switch( flag )
-
{
-
case 'O':
-
{
-
struct pike_string *res;
-
struct Buffer_struct *str = THIS;
-
push_static_text( "Buffer(%d /* %d */)" );
-
if( str->str.s )
-
{
-
push_int(str->str.s->len);
-
push_int(str->str.malloced);
-
}
-
else
-
{
-
push_int( 0 );
-
push_int( 0 );
-
}
-
f_sprintf( 3 );
-
dmalloc_touch_svalue(Pike_sp-1);
-
res = Pike_sp[-1].u.string;
-
Pike_sp--;
-
RETURN res;
-
}
-
-
case 's':
-
{
-
pop_n_elems( args );
-
if( Pike_fp->current_object->refs != 1 )
-
f_Buffer_get_copy( 0 );
-
else
-
f_Buffer_get( 0 );
-
}
-
return;
-
-
case 't':
-
RETURN make_shared_binary_string("Buffer",6);
-
}
-
pop_n_elems( args );
-
push_undefined();
-
}
-
-
/*! @decl mixed cast( string type )
-
*! It is possible to cast a String.Buffer object to
-
*! a @expr{string@} and an @expr{int@}.
-
*/
-
PIKEFUN mixed cast( string type )
-
flags ID_PROTECTED;
-
{
-
if( type == literal_string_string )
-
{
-
pop_stack();
-
if( Pike_fp->current_object->refs != 1 )
-
f_Buffer_get_copy( 0 );
-
else
-
f_Buffer_get( 0 );
-
return;
-
}
-
-
if( type == literal_int_string )
-
{
-
struct Buffer_struct *str = THIS;
-
pop_stack();
-
if( Pike_fp->current_object->refs != 1 )
-
f_Buffer_get_copy( 0 );
-
else
-
f_Buffer_get( 0 );
-
o_cast_to_int( );
-
return;
-
}
-
-
pop_stack();
-
push_undefined();
-
}
-
-
/*! @decl String.Buffer `+( string|String.Buffer what )
-
*/
-
PIKEFUN object `+( string|Buffer what )
-
rawtype tFunc(tOr(tString, tObjIs_BUFFER), tObjIs_BUFFER);
-
{
-
struct Buffer_struct *str = THIS, *str2;
-
struct object *res = fast_clone_object( Buffer_program );
-
str2 = OBJ2_BUFFER( res );
-
str2->initial = str->initial;
-
if( str->str.s )
-
init_string_builder_copy (&str2->str, &str->str);
-
if( (Pike_fp->current_object->flags & OBJECT_CLEAR_ON_EXIT) )
-
res->flags |= OBJECT_CLEAR_ON_EXIT;
-
apply( res, "add", 1 );
-
RETURN res;
-
}
-
-
/*! @decl String.Buffer `+=( string|String.Buffer what )
-
*/
-
PIKEFUN object `+=( string|Buffer what )
-
rawtype tFunc(tOr(tString, tObjIs_BUFFER), tObjIs_BUFFER);
-
{
-
f_Buffer_add( 1 );
-
REF_RETURN Pike_fp->current_object;
-
}
-
-
/*! @decl int add(string|String.Buffer ... data)
-
*!
-
*! Adds @[data] to the buffer.
-
*!
-
*! @returns
-
*! Returns the size of the buffer.
-
*!
-
*! @note
-
*! Pike 7.8 and earlier did not support adding @[String.Buffer]s
-
*! directly.
-
*/
-
PIKEFUN int add( string|Buffer ... arg1 )
-
rawtype tFuncV(tNone, tOr(tString, tObjIs_BUFFER), tIntPos);
-
{
-
struct Buffer_struct *str = THIS;
-
-
if (args) {
-
int init_from_arg0 = 0, j;
-
ptrdiff_t sum = 0;
-
int shift = 0;
-
for (j=0; j < args; j++) {
-
struct pike_string *a;
-
if (TYPEOF(Pike_sp[j-args]) == PIKE_T_STRING)
-
a = Pike_sp[j-args].u.string;
-
else if ((TYPEOF(Pike_sp[j-args]) != PIKE_T_OBJECT) ||
-
(Pike_sp[j-args].u.object->prog != Buffer_program))
-
SIMPLE_ARG_TYPE_ERROR("add", j+1, "string|String.Buffer");
-
else {
-
a = OBJ2_BUFFER(Pike_sp[j-args].u.object)->str.s;
-
if (!a) continue;
-
}
-
sum += a->len;
-
shift |= a->size_shift;
-
}
-
shift |= str->str.known_shift;
-
shift = shift & ~(shift >> 1);
-
/* We know it will be a string that really is this wide. */
-
str->str.known_shift = shift;
-
-
if (!str->str.s) {
-
if (sum <= str->initial)
-
sum = str->initial;
-
else
-
sum <<= 1;
-
-
init_string_builder_alloc(&str->str, sum, shift);
-
} else
-
string_build_mkspace(&str->str, sum, shift);
-
-
for(sum = str->str.s->len, j = 0; j<args; j++) {
-
struct pike_string *a;
-
if (TYPEOF(Pike_sp[j-args]) == PIKE_T_STRING)
-
a = Pike_sp[j-args].u.string;
-
else {
-
a = OBJ2_BUFFER(Pike_sp[j-args].u.object)->str.s;
-
if (!a) continue;
-
}
-
pike_string_cpy(MKPCHARP_STR_OFF(str->str.s, sum), a);
-
sum += a->len;
-
}
-
-
str->str.s->len = sum;
-
}
-
-
RETURN str->str.s ? str->str.s->len : 0;
-
}
-
-
/*! @decl void putchar(int c)
-
*! Appends the character @[c] at the end of the string.
-
*/
-
PIKEFUN void putchar(int c) {
-
struct Buffer_struct *str = THIS;
-
if(!str->str.s)
-
init_string_builder_alloc(&str->str, str->initial, 0);
-
string_builder_putchar(&str->str, c);
-
}
-
-
/*! @decl int sprintf(strict_sprintf_format format, sprintf_args ... args)
-
*! Appends the output from @[sprintf] at the end of the string.
-
*! Returns the resulting size of the String.Buffer.
-
*/
-
PIKEFUN int sprintf(mixed ... arguments)
-
rawtype tFuncV(tAttr("strict_sprintf_format", tOr(tStr, tObj)),
-
tAttr("sprintf_args", tMix), tStr);
-
-
{
-
// FIXME: Reset length on exception?
-
struct Buffer_struct *str = THIS;
-
if(!str->str.s)
-
init_string_builder_alloc(&str->str, str->initial, 0);
-
low_f_sprintf(args, &str->str);
-
RETURN str->str.s->len;
-
}
-
-
/*! @decl string get_copy()
-
*!
-
*! Get the data from the buffer. Significantly slower than @[get],
-
*! but does not clear the buffer.
-
*!
-
*! @seealso
-
*! @[get()]
-
*/
-
PIKEFUN string get_copy()
-
{
-
struct pike_string *str = THIS->str.s;
-
ptrdiff_t len;
-
if( str && (len = str->len) > 0 )
-
{
-
char *d = (char *)str->str;
-
switch( str->size_shift )
-
{
-
case 0:
-
str=make_shared_binary_string0((p_wchar0 *)d,len);
-
break;
-
case 1:
-
str=make_shared_binary_string1((p_wchar1 *)d,len);
-
break;
-
case 2:
-
str=make_shared_binary_string2((p_wchar2 *)d,len);
-
break;
-
}
-
if( Pike_fp->current_object->flags & OBJECT_CLEAR_ON_EXIT )
-
str->flags |= STRING_CLEAR_ON_EXIT;
-
RETURN str;
-
}
-
push_empty_string();
-
return;
-
}
-
-
/*! @decl string get()
-
*!
-
*! Get the data from the buffer.
-
*!
-
*! @note
-
*! This will clear the data in the buffer
-
*!
-
*! @seealso
-
*! @[get_copy()], @[clear()]
-
*/
-
PIKEFUN string get( )
-
{
-
struct Buffer_struct *str = THIS;
-
pop_n_elems(args);
-
if( str->str.s )
-
{
-
struct pike_string *s = finish_string_builder( &str->str );
-
str->str.malloced = 0;
-
str->str.s = NULL;
-
if( Pike_fp->current_object->flags & OBJECT_CLEAR_ON_EXIT )
-
s->flags |= STRING_CLEAR_ON_EXIT;
-
push_string(s);
-
}
-
else
-
push_empty_string();
-
}
-
-
/*! @decl void clear()
-
*!
-
*! Empty the buffer, and don't care about the old content.
-
*!
-
*! @note
-
*! This function was not available in Pike 7.8 and earlier.
-
*!
-
*! @seealso
-
*! @[get()]
-
*/
-
PIKEFUN void clear()
-
{
-
/* FIXME: Support resetting the initial size? */
-
struct Buffer_struct *str = THIS;
-
if (str->str.s) {
-
/* FIXME: There's also the alternative of using
-
* reset_string_builder() here.
-
*/
-
free_string_builder(&str->str);
-
str->str.s = NULL;
-
}
-
}
-
-
/*! @decl int _sizeof()
-
*!
-
*! Returns the size of the buffer.
-
*/
-
PIKEFUN int _sizeof()
-
flags ID_PROTECTED;
-
{
-
struct Buffer_struct *str = THIS;
-
RETURN str->str.s ? str->str.s->len : 0;
-
}
-
-
/*! @decl int(0..) _search(int character, int|void start, int|void end)
-
*!
-
*! Search for a @[character] in the buffer, starting the scan
-
*! from @[start] and ending at @[end] (inclusive).
-
*!
-
*! @returns
-
*! Returns to position in the buffer where the character was found
-
*! on success, and @[UNDEFINED] on failure.
-
*!
-
*! @seealso
-
*! @[Stdio.Buffer()->_search()], @[search()], @[lfun::_search()]
-
*/
-
PIKEFUN int(0..) _search(int character, int|void start, int|void end)
-
{
-
PCHARP buf = MKPCHARP_STR(THIS->str.s);
-
ptrdiff_t len = THIS->str.s->len;
-
ptrdiff_t i;
-
-
if (end && (end->u.integer + 1 < len)) {
-
len = end->u.integer + 1;
-
}
-
if (len > 0 && start && (start->u.integer > 0)) {
-
INC_PCHARP(buf, start->u.integer);
-
len -= start->u.integer;
-
}
-
if (len <= 0) {
-
push_int(-1);
-
return;
-
}
-
if (UNLIKELY(THIS->str.s->size_shift == thirtytwobit)) {
-
#if SIZEOF_INT_TYPE > 4
-
if (UNLIKELY((0x7fffffff < character) || (character < -0x80000000))) {
-
push_int(-1);
-
return;
-
}
-
#endif
-
} else if (UNLIKELY((1L<<(8<<THIS->str.s->size_shift)) <= character) ||
-
UNLIKELY(character < 0)) {
-
push_int(-1);
-
return;
-
}
-
for (i = 0; i < len; i++) {
-
p_wchar2 c = INDEX_PCHARP(buf, i);
-
if (c == character) {
-
if(start)
-
i += start->u.integer;
-
push_int64(i);
-
return;
-
}
-
}
-
push_int(-1);
-
}
-
-
/*! @decl int(0..) _search(string substring, int|void start, int|void end)
-
*!
-
*! Search for a @[substring] in the buffer, starting the scan
-
*! from @[start] and ending at @[end] (inclusive).
-
*!
-
*! @returns
-
*! Returns to position in the buffer where the substring was found
-
*! on success, and @[UNDEFINED] on failure.
-
*!
-
*! @seealso
-
*! @[Stdio.Buffer()->_search()], @[search()], @[lfun::_search()]
-
*/
-
PIKEFUN int(0..) _search(string substring, int|void start, int|void end)
-
{
-
PCHARP buf = MKPCHARP_STR(THIS->str.s);
-
ptrdiff_t len = THIS->str.s->len;
-
ptrdiff_t i;
-
SearchMojt mojt;
-
PCHARP res;
-
-
if (end && (end->u.integer + 1 < len)) {
-
len = end->u.integer + 1;
-
}
-
if (len > 0 && start && (start->u.integer > 0)) {
-
INC_PCHARP(buf, start->u.integer);
-
len -= start->u.integer;
-
}
-
if (len < substring->len) {
-
push_undefined();
-
return;
-
}
-
if (!substring->len) {
-
push_int(0);
-
return;
-
}
-
if (substring->size_shift > THIS->str.s->size_shift) {
-
push_undefined();
-
return;
-
}
-
-
mojt = compile_memsearcher(MKPCHARP_STR(substring), substring->len,
-
len, substring);
-
-
res = mojt.vtab->funcN(mojt.data, buf, len);
-
-
if (!res.ptr) {
-
push_undefined();
-
} else {
-
push_int64((((char *)res.ptr) - ((char *)buf.ptr)) >>
-
THIS->str.s->size_shift);
-
}
-
}
-
-
INIT
-
{
-
struct Buffer_struct *str = THIS;
-
memset( str, 0, sizeof( *str ) );
-
}
-
-
EXIT
-
gc_trivial;
-
{
-
struct Buffer_struct *str = THIS;
-
if( str->str.s )
-
{
-
if( Pike_fp->flags & OBJECT_CLEAR_ON_EXIT )
-
secure_zero( str->str.s->str, str->str.s->len );
-
free_string_builder( &str->str );
-
}
-
}
-
-
GC_RECURSE
-
{
-
if (mc_count_bytes (Pike_fp->current_object) && THIS->str.s)
-
mc_counted_bytes += THIS->str.malloced;
-
}
-
}
-
-
/*! @endclass
-
*/
-
+
/*! @class Replace *! *! This is a "compiled" version of the @[replace] function applied on *! a string, with more than one replace string. The replace strings *! are given to the create method as a @i{from@} and @i{to@} array *! and are then analyzed. The @expr{`()@} is then called with a *! string and the replace rules in the Replace object will be *! applied. The Replace object is used internally by the Pike *! optimizer and need not be used manually. */