pike.git
/
src
/
builtin.cmod
version
»
Context lines:
10
20
40
80
file
none
3
pike.git/src/builtin.cmod:1:
-
/* -*- c -*-
+
/* -*-
mode:
c
;
encoding: utf
-
8; -
*-
|| 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. */ #include "global.h" #include "interpret.h" #include "svalue.h" #include "pike_macros.h" #include "object.h"
pike.git/src/builtin.cmod:19:
#include "pike_types.h" #include "pike_memory.h" #include "threads.h" #include "module_support.h" #include "cyclic.h" #include "bignum.h" #include "main.h" #include "operators.h" #include "builtin_functions.h" #include "fsort.h"
-
#include "
port
.h"
+
#include "
pike_cpulib
.h"
#include "gc.h" #include "block_allocator.h" #include "pikecode.h" #include "opcodes.h"
-
+
#include "whitespace.h"
+
#include "sprintf.h"
+
#include "pike_search.h"
-
#include <ctype.h>
+
#include <errno.h> #include <math.h>
-
+
#include <fcntl.h>
-
DECLARATIONS
+
#ifdef HAVE_ARPA_INET_H
+
#include <arpa/inet.h>
+
#endif /* HAVE_ARPA_INET_H */
-
+
#define DEFAULT_CMOD_STORAGE
-
+
#ifdef STRUCT_TM_HAS___TM_GMTOFF
+
struct tm_extra { };
+
#define tm_zone __tm_zone
+
#define tm_gmtoff __tm_gmtoff
+
#define GET_GMTOFF(TM) ((TM)->tm_gmtoff)
+
#define GET_ZONE(this) ((this)->t.tm_zone)
+
#define SET_GMTOFF(TM, VAL) (((TM)->tm_gmtoff) = (VAL))
+
#define SET_ZONE(this, VAL) ((this)->t.tm_zone = (VAL))
+
#elif defined(STRUCT_TM_HAS_GMTOFF)
+
struct tm_extra { };
+
#define GET_GMTOFF(TM) ((TM)->tm_gmtoff)
+
#define GET_ZONE(this) ((this)->t.tm_zone)
+
#define SET_GMTOFF(TM, VAL) (((TM)->tm_gmtoff) = (VAL))
+
#define SET_ZONE(this, VAL) ((this)->t.tm_zone = (VAL))
+
#else
+
struct tm_extra { const char *tm_zone; };
+
#define GET_GMTOFF(TM) 0
+
#define GET_ZONE(this) ((this)->extra.tm_zone)
+
#define SET_GMTOFF(TM, VAL) (VAL)
+
#define SET_ZONE(this, VAL) ((this)->extra.tm_zone = (VAL))
+
#endif
+
+
DECLARATIONS
+
/*! @module System */
-
#if defined(HAVE_MKTIME) && defined(HAVE_GMTIME) && defined(HAVE_LOCALTIME)
+
/*! @class TM *! A wrapper for the system struct tm time keeping structure. *! This can be used as a (very) lightweight alternative to Calendar. */ PIKECLASS TM { CVAR struct tm t; CVAR time_t unix_time; CVAR int modified;
-
CVAR struct
pike
_
string
*set_zone
;
+
CVAR struct
tm
_
extra
extra
;
-
#ifdef STRUCT_TM_HAS___TM_GMTOFF
-
#define tm_zone __tm_zone
-
#define tm_gmtoff __tm_gmtoff
-
#define GET_GMTOFF(TM) ((TM)->tm_gmtoff)
-
#define GET_ZONE(TM) ((TM)->tm_zone)
-
#define SET_GMTOFF(TM, VAL) (((TM)->tm_gmtoff) = (VAL))
-
#define SET_ZONE(TM, VAL) (((TM)->tm_zone) = (VAL))
-
#elif defined(STRUCT_TM_HAS_GMTOFF)
-
#define GET_GMTOFF(TM) ((TM)->tm_gmtoff)
-
#define GET_ZONE(TM) ((TM)->tm_zone)
-
#define SET_GMTOFF(TM, VAL) (((TM)->tm_gmtoff) = (VAL))
-
#define SET_ZONE(TM, VAL) (((TM)->tm_zone) = (VAL))
-
#else
-
#define GET_GMTOFF(TM) 0
-
#define GET_ZONE(TM) ((char*)NULL)
-
#define SET_GMTOFF(TM, VAL) (VAL)
-
#define SET_ZONE(TM, VAL) (VAL)
-
#endif
-
-
#if 0
-
/* This is supposed to make any timezone work.
-
* However: It does not really work. And makes things even slower than
-
* the calendar module.
-
*/
-
#ifndef HAVE_EXTERNAL_TIMEZONE
-
#define timezone 0
-
#endif
-
#define WITH_ZONE(RETURNTYPE, FUNCTION, ARGUMENTS, CALL ) \
-
static RETURNTYPE FUNCTION##_zone ARGUMENTS \
-
{ \
-
RETURNTYPE res; \
-
int reset = 0; \
-
char *old_zone = NULL; \
-
if( GET_ZONE(x) ) \
-
{ \
-
reset = 1; \
-
old_zone = getenv("TZ"); \
-
setenv("TZ", GET_ZONE(x), 1 ); \
-
tzset(); \
-
SET_GMTOFF(x, timezone); \
-
} \
-
\
-
res = FUNCTION CALL; \
-
\
-
if( reset ) \
-
{ \
-
if( old_zone ) \
-
setenv("TZ", old_zone, 1 ); \
-
else \
-
unsetenv( "TZ" ); \
-
tzset(); \
-
} \
-
return res; \
-
}
-
-
WITH_ZONE(time_t,mktime,( struct tm *x ),(x));
-
WITH_ZONE(struct tm*,localtime,( time_t *t, struct tm *x ),(t));
-
WITH_ZONE(char *,asctime,( struct tm *x ),(x));
-
WITH_ZONE(int,strftime,( char *buffer, size_t max_len, char *format, struct tm *x ),(buffer,max_len,format,x));
-
#ifdef HAVE_STRPTIME
-
WITH_ZONE(char *,strptime,( const char *str, const char *format, struct tm *x ),(str,format,x));
-
#endif
-
#else
+
#define strftime_zone strftime
-
#define mktime_zone mktime
+
#define strptime_zone strptime
-
#define asctime_zone asctime
+
#define localtime_zone(X,Y) localtime(X)
-
#endif
+
#ifndef HAVE_EXTERNAL_TIMEZONE #undef timezone #endif #define MODIFY(X) do{ THIS->modified = 1;THIS->t.X; }while(0) #define FIX_THIS() do { \
-
if(THIS->modified)
{
\
-
THIS->unix
_
time = mktime_zone
(
&
THIS
->t
);
\
-
THIS->modified
=
0;
\
-
} \
+
if(THIS->modified)
\
+
fix
_
tm
(THIS); \
} while(0)
-
+
static void fix_tm(struct TM_struct *this)
+
{
+
const char *tm_zone = GET_ZONE(this);
+
int is_utc_zone = tm_zone && !strcmp(tm_zone, "UTC");
+
if (is_utc_zone)
+
this->t.tm_isdst = 0;
+
this->unix_time = mktime_zone(&this->t, is_utc_zone, 0);
+
this->modified = 0;
+
}
+
#ifdef HAVE_STRPTIME /*! @decl int(0..1) strptime( string(1..255) format, string(1..255) data ) *!
-
*!
Parse
the
given
@[data]
using
the
format
in
@[format]
as
a
date
.
+
*!
@note
+
*!
The
@expr{format@}
and
@expr{data@}
are reversed
.
*!
-
*!
@dl
-
*!
@item %%
-
*! The % character.
-
*!
-
*! @item %a or %A
-
*! The weekday name according to the C locale, in abbreviated
-
*! form or the full name.
-
*!
-
*! @item %b or %B or %h
-
*! The month name according to the C locale, in abbreviated form
-
*! or the full name.
-
*!
-
*! @item %c
-
*! The date and time representation for the C locale.
-
*!
-
*! @item %C
-
*! The century number (0-99).
-
*!
-
*! @item %d or %e
-
*! The day of month (1-31).
-
*!
-
*! @item %D
-
*! Equivalent to %m/%d/%y.
-
*!
-
*! @item %H
-
*! The hour (0-23).
-
*!
-
*! @item %I
-
*! The hour on a 12-hour clock (1-12).
-
*!
-
*! @item %j
-
*! The day number in the year (1-366).
-
*!
-
*! @item %m
-
*! The month number (1-12).
-
*!
-
*! @item %M
-
*! The minute (0-59).
-
*!
-
*! @item %n
-
*! Arbitrary whitespace.
-
*!
-
*! @item %p
-
*! The C locale's equivalent of AM or PM.
-
*!
-
*! @item %R
-
*! Equivalent to %H:%M.
-
*!
-
*! @item %S
-
*! The second (0-60; 60 may occur for leap seconds;
-
*! earlier also 61 was allowed).
-
*!
-
*! @item %t
-
*! Arbitrary whitespace.
-
*!
-
*! @item %T
-
*! Equivalent to %H:%M:%S.
-
*!
-
*! @item %U
-
*! The week number with Sunday the first day of the week (0-53).
-
*!
-
*! @item %w
-
*! The weekday number (0-6) with Sunday = 0.
-
*!
-
*! @item %W
-
*! The week number with Monday the first day of the week (0-53).
-
*!
-
*! @item %x
-
*! The date, using the C locale's date format.
-
*!
-
*! @item %X
-
*! The time, using the C locale's time format.
-
*!
-
*! @item %y
-
*! The year within century (0-99). When a century is not
-
*! otherwise specified, values in the range 69-99 refer to years
-
*! in the twentieth century (1969-1999); values in the range
-
*! 00-68 refer to years in the twenty-first century (2000-2068).
-
*!
-
*! @item %Y
-
*! The year, including century (for example, 1991).
-
*! @enddl
-
*!
+
*!
@seealso
+
*!
@[strptime]
*/ PIKEFUN int(0..1) strptime( string(1..255) format, string(1..255) data ) { if( format->size_shift || data->size_shift ) Pike_error("Only 8bit strings are supported\n"); THIS->modified = 1; if( strptime_zone( data->str, format->str, &THIS->t ) == NULL ) RETURN 0; RETURN 1; }
-
#endif
+
#endif
/* HAVE_STRPTIME */
/*! @decl string(1..255) strftime( string(1..255) format )
-
*! See also @[Gettext.setlocale]
+
*!
-
*!
Convert the structure to a string.
-
*!
-
*! @dl
-
*! @item %a
-
*! The abbreviated weekday name according to the current locale
-
*!
-
*! @item %A
-
*! The full weekday name according to the current locale.
-
*!
-
*! @item %b
-
*! The abbreviated month name according to the current locale.
-
*!
-
*! @item %B
-
*! The full month name according to the current locale.
-
*!
-
*! @item %c
-
*! The preferred date and time representation for the current locale.
-
*!
-
*! @item %C
-
*! The century number (year/100) as a 2-digit integer.
-
*!
-
*! @item %d
-
*! The day of the month as a decimal number (range 01 to 31).
-
*!
-
*! @item %D
-
*! Equivalent to @expr{%m/%d/%y@}. (for Americans only.
-
*! Americans should note that in other countries @expr{%d/%m/%y@}
-
*! is rather common. This means that in international context
-
*! this format is ambiguous and should not be used.)
-
*!
-
*! @item %e
-
*! Like @expr{%d@}
,
the day of the month as a decimal number,
-
*! but a leading zero is replaced by a space
.
-
*!
-
*! @item %E
-
*! Modifier: use alternative format, see below.
-
*!
-
*! @item %F
-
*! Equivalent to %Y-%m-%d (the ISO 8601 date format). (C99)
-
*!
-
*! @item %G
-
*! The ISO 8601 week-based year (see NOTES) with century as a
-
*! decimal number. The 4-digit year corresponding to the ISO
-
*! week number (see @expr{%V@}). This has the same format and
-
*! value as @expr{%Y@}, except that if the ISO week number
-
*! belongs to the previous or next year, that year is used instead.
-
*!
-
*! @item %g
-
*! Like @expr{%G@}, but without century, that is,
-
*! with a 2-digit year (00-99). (TZ)
-
*!
-
*! @item %h
-
*! Equivalent to %b.
-
*!
-
*! @item %H
-
*! The hour as a decimal number using a 24-hour clock (range 00 to 23).
-
*!
-
*! @item %I
-
*! The hour as a decimal number using a 12-hour clock (range 01 to 12).
-
*!
-
*! @item %j
-
*! The day of the year as a decimal number (range 001 to 366).
-
*!
-
*! @item %k
-
*! The hour (24-hour clock) as a decimal number (range 0 to 23);
-
*! single digits are preceded by a blank. (See also @expr{%H@}.)
-
*!
-
*! @item %l
-
*! The hour (12-hour clock) as a decimal number (range 1 to 12);
-
*! single digits are preceded by a blank. (See also @expr{%I@}.)
-
*!
-
*! @item %m
-
*! The month as a decimal number (range 01 to 12).
-
*!
-
*! @item %M
-
*! The minute as a decimal number (range 00 to 59).
-
*!
-
*! @item %n
-
*! A newline character. (SU)
-
*!
-
*! @item %O
-
*! Modifier: use alternative format, see below. (SU)
-
*!
-
*! @item %p
-
*! Either @expr{"AM"@} or @expr{"PM"@} according to the given time
-
*! value, or the corresponding strings for the current locale.
-
*! Noon is treated as @expr{"PM"@} and midnight as @expr{"AM"@}.
-
*!
-
*! @item %P
-
*! Like @expr{%p@} but in lowercase: @expr{"am"@} or @expr{"pm"@}
-
*! or a corresponding string for the current locale.
-
*!
-
*! @item %r
-
*! The time in a.m. or p.m. notation. In the POSIX locale this is
-
*! equivalent to @expr{%I:%M:%S %p@}.
-
*!
-
*! @item %R
-
*! The time in 24-hour notation (@expr{%H:%M@}). (SU)
-
*! For a version including the seconds, see @expr{%T@} below.
-
*!
-
*! @item %s
-
*! The number of seconds since the Epoch,
-
*! 1970-01-01 00:00:00 +0000 (UTC). (TZ)
-
*!
-
*! @item %S
-
*! The second as a decimal number (range 00 to 60).
-
*! (The range is up to 60 to allow for occasional leap seconds.)
-
*!
-
*! @item %t
-
*! A tab character. (SU)
-
*!
-
*! @item %T
-
*! The time in 24-hour notation (@expr{%H:%M:%S@}). (SU)
-
*!
-
*! @item %u
-
*! The day of the week as a decimal, range 1 to 7, Monday being 1.
-
*! See also @expr{%w@}. (SU)
-
*!
-
*! @item %U
-
*! The week number of the current year as a decimal number,
-
*! range 00 to 53, starting with the first Sunday as the first
-
*! day of week 01. See also @expr{%V@} and @expr{%W@}.
-
*!
-
*! @item %V
-
*! The ISO 8601 week number of the current year as a decimal number,
-
*! range 01 to 53, where week 1 is the first week that has at least
-
*! 4 days in the new year. See also @expr{%U@} and @expr{%W@}.
-
*!
-
*! @item %w
-
*! The day of the week as a decimal, range 0 to 6, Sunday being 0.
-
*! See also @expr{%u@}.
-
*! @enddl
+
*!
@seealso
+
*!
@[strftime]
,
@[Gettext
.
setlocale]
*/
-
PIKEFUN string strftime(string(1..255) format)
+
PIKEFUN string
(1..255)
strftime(string(1..255) format)
{
-
char
*
buffer
= xalloc(
8192
)
;
+
char buffer
[
8192
]
;
buffer[0] = 0;
-
strftime_zone(
buffer,
8192
, format->str, &THIS->t
);
-
push_text(
buffer
);
+
strftime_zone(buffer,
sizeof(buffer)
, format->str, &THIS->t);
+
push_text(buffer);
} /*! @decl int(0..60) sec; *! @decl int(0..59) min; *! @decl int(0..59) hour; *! @decl int(1..31) mday; *! @decl int(0..11) mon; *! @decl int year; *! *! The various fields in the structure. Note that setting these
pike.git/src/builtin.cmod:393:
*! When read the fields are always normalized. *! *! Unlike the system struct tm the 'year' field is not year-1900, *! instead it is the actual year. */ PIKEFUN int(0..60) `sec() { FIX_THIS();RETURN THIS->t.tm_sec; } PIKEFUN int(0..59) `min() { FIX_THIS();RETURN THIS->t.tm_min; } PIKEFUN int(0..23) `hour() { FIX_THIS();RETURN THIS->t.tm_hour; } PIKEFUN int(1..31) `mday() { FIX_THIS();RETURN THIS->t.tm_mday; } PIKEFUN int(0..11) `mon() { FIX_THIS();RETURN THIS->t.tm_mon; }
-
PIKEFUN int `year() { FIX_THIS();RETURN THIS->t.tm_year+1900; }
+
-
+
PIKEFUN int `year() { FIX_THIS();RETURN THIS->t.tm_year+1900; }
PIKEFUN int `sec=(int a) { MODIFY(tm_sec=a); } PIKEFUN int `min=(int a) { MODIFY(tm_min=a); } PIKEFUN int `hour=(int a){ MODIFY(tm_hour=a); } PIKEFUN int `mday=(int a){ MODIFY(tm_mday=a); } PIKEFUN int `year=(int a){ MODIFY(tm_year=a-1900); } PIKEFUN int `mon=(int a){ MODIFY(tm_mon=a); } /*! @decl int isdst *!
-
*! True if daylight
savings
are
in effect. If this field is -1
+
*! True if daylight
-saving
is
in effect. If this field is -1
*! (the default) it (and the timezone info) will be updated *! automatically using the timezone rules. */ PIKEFUN int(-1..1) `isdst() { FIX_THIS(); RETURN THIS->t.tm_isdst; } /*! @decl int wday *! The day of the week, sunday is 0, saturday is 6. *! This is calculated from the other fields and can not be changed directly. */ PIKEFUN int(0..6) `wday() { FIX_THIS(); RETURN THIS->t.tm_wday; } /*! @decl int yday *! The day of the year, from 0 (the first day) to 365 *! This is calculated from the other fields and can not be changed directly. */
-
PIKEFUN int(0..365) `yday()
{ FIX_THIS(); RETURN THIS->t.tm_yday; }
+
PIKEFUN int(0..365) `yday() { FIX_THIS(); RETURN THIS->t.tm_yday; }
/*! @decl int unix_time() *! Return the unix time corresponding to this time_t. If no time *! can be parsed from the structure -1 is returned. */ PIKEFUN int unix_time() { FIX_THIS(); RETURN THIS->unix_time; } /*! @decl string asctime() *! Return a string representing the time. Mostly useful for debug *! purposes, the exact format is very locale (see *! @[Gettext.setlocale]) and OS dependent. */ PIKEFUN string asctime() { FIX_THIS(); {
-
char
*tval = asctime
_
zone( &THIS->t )
;
-
if(
tval
)
-
push
_
text(
tval
)
;
-
else
+
#define
STRFTIME_MAXSIZE
26
+
char
s[STRFTIME
_
MAXSIZE]
;
+
if(
!strftime(s,
STRFTIME
_
MAXSIZE,
"%c\n",
&THIS->t
)
)
push_undefined();
-
+
else
+
push_text(s);
} }
-
PIKEFUN
void
_sprintf( int flag, mapping options )
+
PIKEFUN
string
_sprintf( int flag, mapping options )
{
-
int post_sum =
1
;
+
int post_sum =
0
;
switch( flag ) { case 'O':
-
push_text("System.TM(");
+
push_
static_
text("System.TM(");
post_sum = 1; /* fallthrough */ case 's': f_TM_asctime(0);
-
push_text("\n");
-
if( GET_ZONE(
&(
THIS
->t
)
)
)
+
push_
static_
text("\n");
+
if( GET_ZONE(THIS) )
{
-
push_text(" ");
-
push_text( GET_ZONE(
&(
THIS
->t
)
)
);
+
push_
static_
text(" ");
+
push_text( GET_ZONE(THIS) );
f_add( 2 ); } else
-
push_text("");
+
push_
static_
text("");
f_replace( 3 ); break; case 'd': f_TM_unix_time(0); break; default: Pike_error("Can not format as %c", flag ); } if( post_sum ) {
-
push_text(")");
+
push_
static_
text(")");
f_add(3); } }
-
PIKEFUN
mixed
cast( string to )
+
/*! @decl int|string cast(string to)
+
*!
+
*! Casted to an integer @[unix_time] will be returned.
+
*!
+
*! Casting to a string will call @[asctime].
+
*/
+
PIKEFUN
int|string
cast( string to )
+
flags ID_PROTECTED;
{
-
struct pike_string *s_string, *s_int;
-
MAKE_CONST_STRING(s_int, "int");
-
MAKE_CONST_STRING(s_string, "string");
-
if( to ==
s
_int )
+
if( to ==
literal
_int
_string
)
{ f_TM_unix_time(0); return; }
-
if( to ==
s
_string )
+
if( to ==
literal
_string
_string
)
{ f_TM_asctime(0); return; }
-
Pike
_
error
(
"Does
not
know
how
to
cast
to
%s\n",
to->str
);
+
pop
_
stack
(
);
+
push_undefined(
);
} /*! @decl string zone *! *! The timezone of this structure */ PIKEFUN string `zone() { FIX_THIS();
-
if( GET_ZONE(
&(
THIS
->t
)
)
)
-
push_text( GET_ZONE(
&(
THIS
->t
)
)
);
+
if( GET_ZONE(THIS) )
+
push_text( GET_ZONE(THIS) );
else push_undefined(); } /*! @decl int gmtoff *! The offset from GMT for the time in this tm-struct */ PIKEFUN int `gmtoff() { FIX_THIS(); push_int( GET_GMTOFF(&(THIS->t)) ); }
-
/* Setting the zone does not work, so.. */
-
-
/* PIKEFUN string `zone=(string x) { */
-
/* if( THIS->set_zone ) */
-
/* free_string( THIS->set_zone ); */
-
/* THIS->set_zone = x; */
-
/* MODIFY( tm_zone = x->str ); */
-
/* x->refs++; */
-
/* } */
-
+
/*! @decl int(0..1) localtime( int time ) *! Initialize the struct tm to the local time for the specified *! unix time_t. */ PIKEFUN int(0..1) localtime( int _t ) { time_t t = _t; struct tm *res = localtime_zone( &t, &THIS->t );
-
-
/* These are supposedly correctly by localtime_zone. */
-
SET_GMTOFF(res, GET_GMTOFF(&(THIS->t)));
-
SET_ZONE(res, GET_ZONE(&(THIS->t)));
-
+
if( !res ) RETURN 0;
-
+
THIS->t = *res; THIS->modified = 1; RETURN 1; } /*! @decl int(0..1) gmtime( int time ) *! Initialize the struct tm to the UTC time for the specified *! unix time_t. */ PIKEFUN int(0..1) gmtime( int _t ) { time_t t = _t; struct tm *res = gmtime( &t ); if( !res ) RETURN 0; THIS->t = *res;
-
+
SET_ZONE(THIS, "UTC"); /* Override timezone */
THIS->modified = 1; RETURN 1; }
-
/*! @decl void create(int t)
+
/*! @decl
int(0..1) gmtime( Gmp.mpz time )
+
*! Initialize the struct tm to the UTC time for the specified
+
*! unix time_t.
+
*/
+
PIKEFUN int(0..1) gmtime( object(Gmp.mpz)|object(Gmp.bignum) _t )
+
{
+
INT64 t_int64 = 0;
+
time_t t;
+
struct tm *res;
+
+
if (!low_int64_from_bignum(&t_int64, _t))
+
RETURN 0;
+
+
t = t_int64;
+
res = gmtime( &t );
+
+
if( !res )
+
RETURN 0;
+
+
THIS->t = *res;
+
SET_ZONE(THIS, "UTC"); /* Override timezone */
+
THIS->modified = 1;
+
RETURN 1;
+
}
+
+
/*! @decl
void create(int
|Gmp.mpz
t)
*! Create a new @[TM] initialized from a unix time_t. *! The timezone will always be UTC when using this function. */
-
PIKEFUN void create( int _t )
+
PIKEFUN void create( int
|object(Gmp.mpz)|object(Gmp.bignum)
_t )
{ f_TM_gmtime( 1 ); if( Pike_sp[-1].u.integer == 0 ) Pike_error("time out of range\n");
-
+
pop_stack();
} /*! @decl void create() *! Construct a new TM, all fields will be set to 0. */ PIKEFUN void create( ) { memset( &THIS->t, 0, sizeof( struct tm ) ); THIS->t.tm_isdst = -1;
-
+
THIS->t.tm_mday = 1;
THIS->unix_time = 0; THIS->modified = 1; } /*! @decl void create( int year, int(0..11) mon, int(1..31) mday, @ *! int(0..24) hour, int(0..59) min, int(0..59) sec, @ *! string|void timezone ) *! Construct a new time using the given values. *! Slightly faster than setting them individually. */ PIKEFUN void create( int year, int(0..11) mon, int(1..31) mday, int(0..24) hour, int(0..59) min, int(0..59) sec, string|void timezone ) { struct tm *t = &THIS->t;
-
+
int use_utc = 0;
t->tm_isdst = -1; t->tm_year = year - 1900; t->tm_mon = mon; t->tm_mday = mday; t->tm_hour = hour; t->tm_min = min; t->tm_sec = sec;
-
if (
THIS->set_zone
) {
-
free_string
(
THIS
->
set_zone
)
;
-
THIS->set
_
zone
=
NULL
;
+
if (
timezone
) {
+
if
(
strcmp(timezone
->
str, "UTC"
)
)
+
Pike
_
error("Timezone
must either be UTC or omitted.\n");
+
use_utc
=
1
;
}
-
if(
!timezone
)
/*
gmtime.
*/
-
SET
_
ZONE
(t,
"UTC"
);
-
else
-
{
-
add_ref
(
timezone
)
;
-
THIS->set
_
zone
= timezone
;
-
SET
_
ZONE
(
t, timezone->str
);
+
if
(
use_utc)
+
t->tm_isdst
=
0;
+
THIS->unix
_
time = mktime_zone
(
&THIS->
t,
use_utc, 0
);
+
/*
Setting
it
to
other
timezones
than
UTC
is
not
supported
(yet)
*/
+
if (use
_
utc
)
+
SET_ZONE(
THIS
,
"UTC")
;
+
pop
_
n_elems
(
args
);
}
-
THIS->unix_time = mktime_zone( t );
-
}
+
-
+
#ifdef PIKE_NULL_IS_SPECIAL
INIT {
-
THIS->set_zone = 0;
+
THIS->modified = 0; }
-
-
EXIT {
-
if( THIS->set_zone )
-
free_string( THIS->set_zone );
+
#endif
}
-
}
+
/*! @endclass */ #undef FIX_THIS #ifdef STRUCT_TM_HAS___TM_GMTOFF #undef tm_zone #undef tm_gmtoff #endif
-
#endif
+
/*! @endmodule */ /*! @decl array(array(int|string|type)) describe_program(program p) *! @belongs Debug *! *! Debug function for showing the symbol table of a program. *! *! @returns *! Returns an array of arrays with the following information
pike.git/src/builtin.cmod:692:
*/ PMOD_EXPORT PIKEFUN array(array(int|string)) _describe_program(mixed x) efun; { struct program *p; struct array *res; int i; if (!(p = program_from_svalue(Pike_sp - args)))
-
SIMPLE_
BAD_
ARG_ERROR("_describe_program", 1, "program");
+
SIMPLE_ARG_
TYPE_
ERROR("_describe_program", 1, "program");
for (i=0; i < (int)p->num_identifier_references;i++) { struct reference *ref = p->identifier_references + i; struct identifier *id = ID_FROM_PTR(p, ref); struct inherit *inh = INHERIT_FROM_PTR(p, ref); push_int(ref->id_flags); ref_push_string(id->name); ref_push_type_value(id->type); push_int(id->identifier_flags); if (IDENTIFIER_IS_C_FUNCTION(id->identifier_flags)) {
pike.git/src/builtin.cmod:749:
f_aggregate_mapping(0); apply_low(x->u.object, fun + p->inherits[SUBTYPEOF(*x)].identifier_level, 2); if(TYPEOF(Pike_sp[-1]) == T_STRING) { stack_swap(); pop_stack(); return; } else if (UNSAFE_IS_ZERO(Pike_sp-1)) { pop_n_elems(2);
-
push_
constant_text
(
"
object
"
);
+
ref_
push_
string(literal
_object
_string
);
return; } else { Pike_error("Non-string returned from _sprintf()\n"); } } } pop_stack(); switch(t) {
-
case T_ARRAY: push_
constant_text
(
"
array
"
); break;
-
case T_FLOAT: push_
constant_text
(
"
float
"
); break;
-
case T_FUNCTION: push_
constant_text
(
"
function
"
); break;
-
case T_INT: push_
constant_text
(
"
int
"
); break;
-
case T_MAPPING: push_
constant_text
(
"
mapping
"
); break;
-
case T_MULTISET: push_
constant_text
(
"
multiset
"
); break;
-
case T_OBJECT: push_
constant_text
(
"
object
"
); break;
-
case T_PROGRAM: push_
constant_text
(
"
program
"
); break;
-
case T_STRING: push_
constant_text
(
"
string
"
); break;
-
case T_TYPE: push_
constant_text
(
"
type
"
); break;
+
case T_ARRAY:
ref_
push_
string(literal
_array
_string
); break;
+
case T_FLOAT:
ref_
push_
string(literal
_float
_string
); break;
+
case T_FUNCTION:
ref_
push_
string(literal
_function
_string
); break;
+
case T_INT:
ref_
push_
string(literal
_int
_string
); break;
+
case T_MAPPING:
ref_
push_
string(literal
_mapping
_string
); break;
+
case T_MULTISET:
ref_
push_
string(literal
_multiset
_string
); break;
+
case T_OBJECT:
ref_
push_
string(literal
_object
_string
); break;
+
case T_PROGRAM:
ref_
push_
string(literal
_program
_string
); break;
+
case T_STRING:
ref_
push_
string(literal
_string
_string
); break;
+
case T_TYPE:
ref_
push_
string(literal
_type
_string
); break;
case T_ZERO: push_constant_text("zero"); break; case T_VOID: push_constant_text("void"); break; /* The following are internal and shouldn't be applicable in normal use. */
-
case T_SVALUE_PTR: push_
constant
_text("svalue_ptr"); break;
-
case T_OBJ_INDEX: push_
constant
_text("obj_index"); break;
-
case T_MAPPING_DATA: push_
constant
_text("mapping_data"); break;
-
case T_PIKE_FRAME: push_
constant
_text("pike_frame"); break;
-
case T_MULTISET_DATA: push_
constant
_text("multiset_data"); break;
-
default: push_
constant
_text("unknown"); break;
+
case T_SVALUE_PTR: push_
static
_text("svalue_ptr"); break;
+
case T_OBJ_INDEX: push_
static
_text("obj_index"); break;
+
case T_MAPPING_DATA: push_
static
_text("mapping_data"); break;
+
case T_PIKE_FRAME: push_
static
_text("pike_frame"); break;
+
case T_MULTISET_DATA: push_
static
_text("multiset_data"); break;
+
default: push_
static
_text("unknown"); break;
} }
-
+
/*! @decl int siphash24(string data, void|int key)
+
*! @appears Crypto.siphash24
+
*!
+
*! Hashes a string, with an optional key, to a 64 bit integer using
+
*! the siphash-2-4 algorithm. Currently the 64 bit @[key] parameter
+
*! is used both for the high and low part of the 128 bit key.
+
*!
+
*/
+
#include "siphash24.h"
+
PIKEFUN int siphash24(string s, void|int key)
+
{
+
mpz_t ret;
+
mpz_init(ret);
+
mpz_set_ui(ret, pike_string_siphash24(s, key && key->u.integer) );
+
push_bignum(ret);
+
}
/*! @decl string int2char(int x) *! @appears String.int2char *! *! Same as sprintf("%c",x); *! *! @seealso *! @[sprintf()] */ PMOD_EXPORT PIKEFUN string int2char(int|object x) efun; optflags OPT_TRY_OPTIMIZE;
-
+
rawtype tFunc(tSetvar(0, tOr(tInt,tObj)), tNStr(tVar(0)));
{ int c; struct program *p; if(TYPEOF(*x) == T_OBJECT && (p = x->u.object->prog)) { ptrdiff_t fun = FIND_LFUN(p->inherits[SUBTYPEOF(*x)].prog, LFUN__SPRINTF); if(fun != -1) { push_int('c'); f_aggregate_mapping(0);
pike.git/src/builtin.cmod:816:
if(TYPEOF(Pike_sp[-1]) == T_STRING) { stack_swap(); pop_stack(); return; } Pike_error("Non-string returned from _sprintf()\n"); } } if(TYPEOF(*x) != T_INT)
-
SIMPLE_
BAD_
ARG_ERROR("int2char", 1, "int");
+
SIMPLE_ARG_
TYPE_
ERROR("int2char", 1, "int");
c=x->u.integer; if(c>=0 && c<256) { struct pike_string *s; s=begin_shared_string(1); s->str[0]=c; RETURN end_shared_string(s); }else{
pike.git/src/builtin.cmod:873:
if(TYPEOF(Pike_sp[-1]) == T_STRING) { stack_swap(); pop_stack(); return; } Pike_error("Non-string returned from _sprintf()\n"); } } if(TYPEOF(*x) != T_INT)
-
SIMPLE_
BAD_
ARG_ERROR("int2hex", 1, "int");
+
SIMPLE_ARG_
TYPE_
ERROR("int2hex", 1, "int");
c=x->u.integer; len=1; if(c<0) { len++; n=(-c)&((unsigned INT_TYPE)(-1)); }else{ n=c; }
pike.git/src/builtin.cmod:909:
while(len && n) { s->str[--len]="0123456789abcdef"[n&0xf]; n>>=4; } } RETURN end_shared_string(s); }
-
/*! @decl string string2hex(string data)
+
/*! @decl string string2hex(string data
, void|int(0..
)
flags)
*! @appears String.string2hex *! *! Convert a string of binary data to a hexadecimal string. *!
-
+
*! @param flags
+
*! The binary or of the following flags:
+
*! @int
+
*! @value 1
+
*! Use upper case characters.
+
*!
+
*! @value 2
+
*! The input is in little-endian byte order.
+
*! @endint
+
*!
*! @seealso *! @[hex2string()] */ static const char hexchar[] = { '0','1','2','3','4','5','6','7','8','9', 'a','b','c','d','e','f' };
-
static const
unsigned
char
hexdecode
[
256
] =
-
{
-
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-
-
/*
'0'
-
'
9
'
*/
-
0
,
1,
2,
3,
4,
5,
6,
7,
8,
9,
-
-
0,0,0,0,0,0,0,
-
-
/*
'A'
-
'
F
'
*/
-
10
,
11
,
12, 13, 14, 15,
-
-
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
-
/*
'
a
'
-
'
f
'
*/
-
10
,
11, 12, 13, 14, 15,
+
static const char
HEXCHAR
[] =
{
+
'0'
,
'
1
',
'
2
'
,
'
3
'
,
'
4
'
,
'
5
'
,
'
6
'
,
'
7
'
,
'
8
'
,
'
9
'
,
+
'A'
,
'
B
',
'C'
,
'D'
,'
E
'
,
'
F
'
}; PMOD_EXPORT
-
PIKEFUN string(
0
..
255
) string2hex(string s)
-
errname String.string2hex
;
+
PIKEFUN string(
48
..
102
) string2hex(string s
, void|int flags
)
+
efun
;
optflags OPT_TRY_OPTIMIZE; { struct pike_string *hex; unsigned char *p,*st = (unsigned char *)s->str;
-
int i, l;
+
const char *hextab = hexchar;
+
int i, l
, d = 1
;
if (s->size_shift) Pike_error("Bad argument 1 to string2hex(), expected 8-bit string.\n");
-
+
if (flags && (flags->u.integer & 1)) {
+
hextab = HEXCHAR;
+
}
+
hex = begin_shared_string(2 * s->len); p = (unsigned char *)hex->str; l = s->len;
-
+
if (flags && (flags->u.integer & 2)) {
+
d = -1;
+
st += l-1;
+
}
+
for (i=0; i<l; i++) {
-
*p++ =
hexchar
[*st>>4];
-
*p++ =
hexchar
[*st&15];
-
st++
;
+
*p++ =
hextab
[*st>>4];
+
*p++ =
hextab
[*st&15];
+
st += d
;
} RETURN end_shared_string(hex); }
-
/*! @decl string hex2string(string hex)
+
extern const unsigned char hexdecode[256];
+
+
/*! @decl string
(8bit)
hex2string(string
(8bit)
hex)
*! @appears String.hex2string *!
-
*! Convert a string of hexadecimal digits to binary data.
+
*! Convert a string of hexadecimal digits to binary
+
*!
data.
Non-hexadecimal characters will be ignored when between
+
*! tuples. Eg. "00 00" is ok, but "0 000" isn't.
*! *! @seealso *! @[string2hex()] */ PMOD_EXPORT PIKEFUN string(0..255) hex2string(string hex)
-
errname String.hex2string;
+
optflags OPT_TRY_OPTIMIZE; { struct pike_string *s; int tmp, i; unsigned char *p, *q = (unsigned char *)hex->str;
-
int l = hex->len
>>1
;
-
if(hex->size_shift) Pike_error("
Only
hex
digits
allowed.\n");
-
if(hex->len&1) Pike_error("Can't have odd number of digits.\n");
+
int l =
i =
hex->len;
+
if(hex->size_shift) Pike_error("
Wide
strings
are
not
allowed.\n");
-
s = begin_shared_string(l);
+
s = begin_shared_string(l
>>1
);
p = (unsigned char *)s->str;
-
for
(
i=0;
i<
l
;
i++
)
+
while
( l
> 1
)
{ tmp = hexdecode[*q++];
-
*
p++
=
(
tmp<<4
)
|
hexdecode[*q++];
+
if( tmp==16 ) { l--; i--; continue; }
+
*
p
= tmp<<4
;
+
tmp =
hexdecode[*q++];
+
if( tmp==16 ) Pike_error("Illegal hex format.\n");
+
*p++ |= tmp;
+
l -= 2;
}
-
+
if( l && hexdecode[*q]!=16 )
+
Pike_error("Illegal hex format.\n");
+
+
if( hex->len>>1 == i>>1 )
RETURN end_shared_string(s);
-
+
else
+
RETURN end_and_resize_shared_string(s, i>>1);
}
-
+
/*! @decl array(int) range(string s)
+
*! @appears String.range
+
*!
+
*! Returns the character range of a string in an array of two
+
*! elements. The first element contains the lower bound and the
+
*! second the upper. The precision is only 8 bits, so for wide
+
*! strings only character blocks are known.
+
*/
+
PIKEFUN array(int) string_range(string s)
+
errname range;
+
optflags OPT_TRY_OPTIMIZE;
+
{
+
int min, max;
+
check_string_range(s, 0, &min, &max);
+
pop_n_elems(args);
+
push_int(min);
+
push_int(max);
+
f_aggregate(2);
+
}
+
/*! @decl array column(array data, mixed index) *! *! Extract a column from a two-dimensional array. *! *! This function is exactly equivalent to: *! @code *! map(@[data], lambda(mixed x,mixed y) { return x[y]; }, @[index]) *! @endcode *! *! Except of course it is a lot shorter and faster.
pike.git/src/builtin.cmod:1106:
{ INT32 old_level; if (facility) { struct pike_string *gc_str; MAKE_CONST_STRING(gc_str, "gc"); if (facility == gc_str) { old_level = gc_trace; gc_trace = level; } else {
-
bad_arg_error("trace",
Pike_sp-
args,
args,
2,
+
bad_arg_error("trace", args, 2,
"trace facility identifier", Pike_sp-args+1, "Bad argument 2 to trace(). Unknown trace facility."); } } else { old_level = Pike_interpreter.trace_level; #ifdef PIKE_THREADS if (!all_threads) Pike_interpreter.trace_level = level; else {
pike.git/src/builtin.cmod:1176:
*! @member float "average_slowness" *! When predicting the next gc interval, use a decaying average *! with this slowness factor. It should be a value between 0.0 and *! 1.0 that specifies the weight to give to the old average value. *! The remaining weight up to 1.0 is given to the last reading. *! @member function(:void) "pre_cb" *! This function is called when the gc starts. *! @member function(:void) "post_cb" *! This function is called when the mark and sweep pass of the gc *! is done.
-
*! @member function(object:void) "destruct_cb"
+
*! @member function(object
,int,int
:void) "destruct_cb"
*! This function is called once for each object that is part of *! a cycle just before the gc will destruct it.
-
+
*! The arguments are:
+
*! @dl
+
*! @item
+
*! The object to be destructed.
+
*! @item
+
*! The reason for it being destructed. One of:
+
*! @int
+
*! @value Object.DESTRUCT_CLEANUP
+
*! Destructed during exit.
+
*! @value Object.DESTRUCT_GC
+
*! Destructed during normal implicit or explicit @[gc()].
+
*! @endint
+
*! @item
+
*! The number of references it had.
+
*! @enddl
*! @member function(int:void) "done_cb" *! This function is called when the gc is done and about to exit. *! The argument is the same value as will be returned by gc(). *! @endmapping *! *! @seealso *! @[gc], @[Debug.gc_status] */ PMOD_EXPORT PIKEFUN mapping(string:mixed) gc_parameters (void|mapping(string:mixed) params)
-
errname Pike.gc_parameters;
+
optflags OPT_SIDE_EFFECT; { struct pike_string *str; struct svalue *set; struct svalue get; if (!params) { push_mapping (allocate_mapping (6)); params = Pike_sp[-1].u.mapping; }
pike.git/src/builtin.cmod:1216:
else { \ GET; \ mapping_string_insert (params, str, &get); \ } \ } while (0) #define HANDLE_FLOAT_FACTOR(NAME, VAR) \ HANDLE_PARAM (NAME, { \ if (TYPEOF(*set) != T_FLOAT || \ set->u.float_number < 0.0 || set->u.float_number > 1.0) \
-
SIMPLE_
BAD_
ARG_ERROR ("
Pike.
gc_parameters", 1, \
+
SIMPLE_ARG_
TYPE_
ERROR ("gc_parameters", 1,
\
"float between 0.0 and 1.0 for " NAME); \
-
VAR =
DO_NOT_WARN
(
(
double) set->u.float_number
)
; \
+
VAR = (double) set->u.float_number;
\
}, { \
-
SET_SVAL(get, T_FLOAT, 0, float_number,
\
-
DO_NOT_WARN
(
(
FLOAT_TYPE) VAR)
)
;
\
+
SET_SVAL(get, T_FLOAT, 0, float_number, (FLOAT_TYPE) VAR); \
}); HANDLE_PARAM ("enabled", { if (TYPEOF(*set) != T_INT || set->u.integer < -1 || set->u.integer > 1)
-
SIMPLE_
BAD_
ARG_ERROR ("
Pike.
gc_parameters", 1,
+
SIMPLE_ARG_
TYPE_
ERROR ("gc_parameters", 1,
"integer in the range -1..1 for 'enabled'"); if (gc_enabled != set->u.integer) { if (gc_enabled > 0) { /* Disabling automatic gc - save the old alloc_threshold and set it to * the maximum value to avoid getting gc_evaluator_callback added. */ saved_alloc_threshold = alloc_threshold; alloc_threshold = GC_MAX_ALLOC_THRESHOLD; } else if (set->u.integer > 0) { /* Enabling automatic gc - restore the old alloc_threshold. If the
pike.git/src/builtin.cmod:1290:
*! *! Convert the output from a previous call to @[time()] into a readable *! string containing the current year, month, day and time. *! *! Like @[localtime], this function might throw an error if the *! ctime(2) call failed on the system. It's platform dependent what *! time ranges that function can handle, e.g. Windows doesn't handle *! a negative @[timestamp]. *! *! @seealso
-
*! @[time()], @[localtime()], @[
mktime
()], @[
gmtime
()]
+
*!
@[
strftime()], @[
time()], @[localtime()], @[
gmtime
()], @[
mktime
()]
*/ PMOD_EXPORT PIKEFUN string ctime(longest timestamp) efun; optflags OPT_TRY_OPTIMIZE; { time_t i; char *s;
-
#if SIZEOF_TIME_T < SIZEOF_
LONGEST
+
#if SIZEOF_TIME_T < SIZEOF_
INT64
if (timestamp > MAX_TIME_T || timestamp < MIN_TIME_T) SIMPLE_ARG_ERROR ("ctime", 1, "Timestamp outside valid range."); #endif i = (time_t) timestamp; s = ctime (&i); if (!s) Pike_error ("ctime() on this system cannot handle " "the timestamp %ld.\n", (long) i); RETURN make_shared_string(s); }
pike.git/src/builtin.cmod:1331:
*! *! @seealso *! @[indices()], @[values()] */ PMOD_EXPORT PIKEFUN mapping(1:2) mkmapping(array(1=mixed) ind, array(2=mixed) val) efun; optflags OPT_TRY_OPTIMIZE|OPT_EXTERNAL_DEPEND; { if(ind->size != val->size)
-
bad_arg_error("mkmapping",
Pike_sp-
args,
args,
2, "array", Pike_sp+1-args,
+
bad_arg_error("mkmapping", args, 2, "array", Pike_sp+1-args,
"mkmapping called on arrays of different sizes (%d != %d)\n", ind->size, val->size); RETURN mkmapping(ind, val); }
-
/*! @decl
void
secure(string str)
+
/*! @decl
string
secure(string str)
*! @belongs String *! *! Marks the string as secure, which will clear the memory area *! before freeing the string.
-
+
*!
+
*! @seealso
+
*! @[Object.secure()]
*/ PIKEFUN string string_secure(string str) optflags OPT_SIDE_EFFECT; rawtype tFunc(tSetvar(0, tStr), tVar(0)); { str->flags |= STRING_CLEAR_ON_EXIT; REF_RETURN str; }
-
+
/*! @decl object secure(object str)
+
*! @belongs Object
+
*!
+
*! Marks the object as secure, which will clear the memory area
+
*! before freeing the object.
+
*!
+
*! @seealso
+
*! @[String.secure()]
+
*/
+
PIKEFUN object object_secure(object obj)
+
optflags OPT_SIDE_EFFECT;
+
rawtype tFunc(tSetvar(0, tObj), tVar(0));
+
{
+
obj->flags |= OBJECT_CLEAR_ON_EXIT;
+
REF_RETURN obj;
+
}
+
/*! @decl int count(string haystack, string needle) *! @belongs String *! *! Count the number of non-overlapping times the string @[needle] *! occurs in the string @[haystack]. The special cases for the needle *! @expr{""@} is that it occurs one time in the empty string, zero *! times in a one character string and between every character *! (length-1) in any other string. *! *! @seealso *! @[search()], @[`/()] */ PMOD_EXPORT PIKEFUN int string_count(string haystack, string needle)
-
errname
String.
count;
+
errname count;
optflags OPT_TRY_OPTIMIZE; { ptrdiff_t c = 0; ptrdiff_t i, j; switch (needle->len) { case 0: switch (haystack->len) {
pike.git/src/builtin.cmod:1395:
default: for (i=0; i<haystack->len; i++) { j=string_search(haystack,needle,i); if (j==-1) break; i=j+needle->len-1; c++; } break; }
-
RETURN
DO_NOT_WARN
(
(
INT_TYPE)c
)
;
+
RETURN (INT_TYPE)c;
} /*! @decl string trim_whites (string s) *! @belongs String *! *! Trim leading and trailing spaces and tabs from the string @[s]. */ PMOD_EXPORT PIKEFUN string string_trim_whites (string s)
-
errname
String.
trim_whites;
+
errname trim_whites;
optflags OPT_TRY_OPTIMIZE; { ptrdiff_t start = 0, end = s->len; int chr; switch (s->size_shift) { #define DO_IT(TYPE) \ { \ for (; start < s->len; start++) { \ chr = ((TYPE *) s->str)[start]; \ if (chr != ' ' && chr != '\t') break; \
pike.git/src/builtin.cmod:1455:
*! @note *! Trailing and leading whitespace around \r and \n characters *! is stripped as well (only useful if they're not in the @[whitespace] set). *! *! @note *! This function is a lot faster with just one argument (i.e. the builtin *! whitespace set has an optimised code path). */ PMOD_EXPORT PIKEFUN string string_normalize_space (string s, string|void whitespace)
-
errname
String.
normalize_space;
+
errname normalize_space;
optflags OPT_TRY_OPTIMIZE; { size_t len = s->len, wlen; const void *src = s->str; unsigned shift = s->size_shift, replspace; const void *ws; void *wstemp = 0; struct string_builder sb; unsigned foundspace = 0; wlen = replspace = 0; /* useless, but suppresses silly compiler warning */ { unsigned bshift = shift, wshift;
-
if(whitespace)
-
if(!(wlen = whitespace->len))
+
if(whitespace)
{
+
if(!(wlen = whitespace->len))
{
REF_RETURN s;
-
else {
+
}
else {
ws = whitespace->str; wshift = whitespace->size_shift; replspace = index_shared_string(whitespace, 0); if(replspace > 0xffff) bshift = 2; else if(replspace > 0xff && !bshift) bshift = 1; if(wshift!=shift) { /* convert whitespace to shift of input */ PCHARP pcnws; wstemp = xalloc(wlen<<shift); pcnws = MKPCHARP(wstemp, shift);
pike.git/src/builtin.cmod:1498:
do { unsigned chr = INDEX_PCHARP(pcows, i++); if (chr<=0xff || (chr<=0xffff && shift)) /* shift is 0 or 1 */ SET_INDEX_PCHARP(pcnws, wlen++, chr); } while(--clen); } else pike_string_cpy(pcnws, whitespace); ws = wstemp; } }
-
else
+
}
else
ws = 0; init_string_builder_alloc (&sb, len, bshift); if(bshift == shift) sb.known_shift = bshift; }
-
#define SPACECASE8 \
-
case ' ':case '\t':case '\r':case '\n':case '\v':case '\f': \
-
case 0x85:case 0xa0:
-
#include "whitespace.h"
+
switch (shift) { #define NORMALISE_TIGHT_LOOP(TYPE,CASE) \ { \ const TYPE *start = src, *end = start+len; \ if (!ws) { \ TYPE *dst = (void*)sb.s->str; \ for (; start < end; start++) { \ switch(*start) { \ CASE \
pike.git/src/builtin.cmod:1573:
} \ string_builder_putchar(&sb, chr); foundspace=0; \ skip##TYPE:; \ } \ } \ } case 0: NORMALISE_TIGHT_LOOP (p_wchar0,SPACECASE8); break; case 1: NORMALISE_TIGHT_LOOP (p_wchar1,SPACECASE16); break; case 2: NORMALISE_TIGHT_LOOP (p_wchar2,SPACECASE16); break; #undef NORMALISE_TIGHT_LOOP
-
#undef SPACECASE8
-
#undef SPACECASE16
+
} if (wstemp) free(wstemp); if (foundspace) sb.s->len--; RETURN finish_string_builder (&sb); }
-
/*! @decl string trim
_all_whites
(string s)
+
/*! @decl string trim (string s)
*! @belongs String *! *! Trim leading and trailing white spaces characters (space, tab, *! newline, carriage return, form feed, vertical tab and all the *! white spaces defined in Unicode) from the string @[s]. */ PMOD_EXPORT
-
PIKEFUN string string_trim
_all_whites
(string s)
-
errname
String.
trim
_all_whites
;
+
PIKEFUN string string_trim (string s)
+
errname trim;
optflags OPT_TRY_OPTIMIZE; { ptrdiff_t start = 0, end = s->len; int chr; switch (s->size_shift) {
-
#define SPACECASE8 \
-
case ' ':case '\t':case '\r':case '\n':case '\v':case '\f': \
-
case 0x85:case 0xa0:
-
#include "whitespace.h"
+
#define DO_IT(TYPE,CASE) \ { \ for (; start < end; start++) { \ chr = ((TYPE *) s->str)[start]; \ switch(chr) { \ CASE \ continue; \ } \ break; \
pike.git/src/builtin.cmod:1626:
CASE \ continue; \ } \ break; \ } \ } case 0: DO_IT (p_wchar0,SPACECASE8); break; case 1: DO_IT (p_wchar1,SPACECASE16); break; case 2: DO_IT (p_wchar2,SPACECASE16); break; #undef DO_IT
-
#undef SPACECASE8
-
#undef SPACECASE16
+
} RETURN string_slice (s, start, end + 1 - start); } /*! @decl string status(int verbose) *! @belongs String *! *! Get string table statistics. *! *! @returns
pike.git/src/builtin.cmod:1650:
*! *! @note *! Currently returns the empty string (@expr{""@}) *! if @[verbose] is zero. *! *! @note *! The formatting and contents of the result *! may vary between different versions of Pike. */ PIKEFUN string string_status(int verbose)
-
errname
String.
status;
+
errname status;
{ RETURN add_string_status(verbose); } /*! @decl int implements(program prog, program api) *! @belongs Program *! *! Returns 1 if @[prog] implements @[api]. */ PMOD_EXPORT PIKEFUN int program_implements(program prog, program api)
-
errname
Program.
implements;
+
errname implements;
optflags OPT_TRY_OPTIMIZE; { RETURN implements(prog, api); } /*! @decl int inherits(program|object child, program parent) *! @belongs Program *! *! Returns 1 if @[child] has inherited @[parent]. */ PMOD_EXPORT PIKEFUN int program_inherits(program|object child, program parent)
-
errname
Program.
inherits;
+
errname inherits;
optflags OPT_TRY_OPTIMIZE; { struct program *p = program_from_svalue(child); if (!p)
-
SIMPLE_ARG_TYPE_ERROR("
Program.
inherits", 1, "program|object");
+
SIMPLE_ARG_TYPE_ERROR("inherits", 1, "program|object");
RETURN low_get_storage(p, parent) != -1; } /*! @decl string defined(program p) *! @belongs Program *! *! Returns a string with filename and linenumber describing where *! the program @[p] was defined. *! *! The returned string is of the format @expr{"filename:linenumber"@}. *! *! If it cannot be determined where the program was defined, @expr{0@} *! (zero) will be returned. */ PMOD_EXPORT PIKEFUN string program_defined(program p)
-
errname
Program.
defined;
+
errname defined;
optflags OPT_TRY_OPTIMIZE; { INT_TYPE line; struct pike_string *tmp = low_get_program_line(p, &line); pop_n_elems(args); if (tmp) { push_string(tmp); if(line >= 1) {
-
push_
constant
_text(":");
+
push_
static
_text(":");
push_int(line); f_add(3); } } else push_int(0); } /*! @decl int(8..8)|int(16..16)|int(32..32) width(string s) *! @belongs String
pike.git/src/builtin.cmod:1742:
*! The string @[s] contains characters >= 65536. *! @endint *! *! @note *! It is possible that a future version of Pike may return *! further values. In particular the width @expr{7@} seems *! like it could be useful. */ PMOD_EXPORT PIKEFUN int(8 .. 8)|int(16 .. 16)|int(32 .. 32) string_width(string s)
-
errname
String.
width;
+
errname width;
optflags OPT_TRY_OPTIMIZE; { RETURN 8 * (1 << s->size_shift); } /*! @decl mixed m_delete(object|mapping map, mixed index) *! *! If @[map] is an object that implements @[lfun::_m_delete()], *! that function will be called with @[index] as its single argument. *!
pike.git/src/builtin.cmod:1788:
pop_n_elems(args); *Pike_sp=s; Pike_sp++; dmalloc_touch_svalue(Pike_sp-1); } else if (TYPEOF(*map) == T_OBJECT && (p = map->u.object->prog)) { int id = FIND_LFUN(p->inherits[SUBTYPEOF(*map)].prog, LFUN__M_DELETE); if( id == -1 )
-
SIMPLE_
BAD_
ARG_ERROR("m_delete", 1, "object containing the _m_delete method");
+
SIMPLE_ARG_
TYPE_
ERROR("m_delete", 1, "object containing the _m_delete method");
apply_low(map->u.object, id + p->inherits[SUBTYPEOF(*map)].identifier_level, 1); stack_swap(); pop_stack(); } else {
-
SIMPLE_
BAD_
ARG_ERROR("m_delete", 1, "object|mapping");
+
SIMPLE_ARG_
TYPE_
ERROR("m_delete", 1, "object|mapping");
} }
-
+
/*! @decl void m_clear(mapping map)
+
*!
+
*! Clear the contents of a mapping.
+
*!
+
*! This function clears the content of the mapping @[map] so
+
*! that it becomes empty. This is an atomic operation.
+
*!
+
*! @seealso
+
*! @[m_delete()]
+
*/
+
PMOD_EXPORT
+
PIKEFUN void m_clear(mapping map)
+
efun
+
optflags OPT_SIDE_EFFECT;
+
{
+
/* FIXME: Add an LFUN__M_CLEAR analogous with LFUN__M_DELETE? */
+
clear_mapping(map);
+
}
+
/*! @decl int get_weak_flag(array|mapping|multiset m) *! *! Returns the weak flag settings for @[m]. It's a combination of *! @[Pike.WEAK_INDICES] and @[Pike.WEAK_VALUES]. */ PMOD_EXPORT PIKEFUN int get_weak_flag(array m) efun; optflags OPT_EXTERNAL_DEPEND; {
pike.git/src/builtin.cmod:1832:
} /*! @decl program __empty_program(int|void line, string|void file) */ PIKEFUN program __empty_program(int|zero|void line, string|void file) efun; optflags OPT_EXTERNAL_DEPEND; { struct program *prog = low_allocate_program(); if (file) ext_store_program_line (prog, line, file);
-
#if 0
-
push_program (prog);
-
safe_pike_fprintf (stderr, "Creating empty program %O (%x)\n",
-
Pike_sp - 1, Pike_sp[-1].u.program);
-
Pike_sp--;
-
#endif
+
RETURN prog; } /* Cut the string at the first NUL. */ static struct pike_string *delambda(struct pike_string *str) { PCHARP pcharp = MKPCHARP_STR(str); ptrdiff_t len = pcharp_strlen(pcharp); if (len == str->len) { /* Common case. */
pike.git/src/builtin.cmod:1875:
PIKEFUN string function_name(program|function func) efun; optflags OPT_TRY_OPTIMIZE; { int f = -1; struct program *p = NULL; switch(TYPEOF(*func)) { default:
-
SIMPLE_
BAD_
ARG_ERROR("function_name", 1, "function|program");
-
return;
/* NOTREACHED */
+
SIMPLE_ARG_
TYPE_
ERROR("function_name", 1, "function|program");
+
UNREACHABLE(
return
)
;
case PIKE_T_PROGRAM: { p = func->u.program; if(p->parent) { int e; p=p->parent; /* search constants in parent for this
pike.git/src/builtin.cmod:1919:
dump_program_tables(func->u.program->parent, 0); } #endif } break; } case PIKE_T_FUNCTION: if((f = SUBTYPEOF(*func)) == FUNCTION_BUILTIN) break; if(!(p = func->u.object->prog))
-
bad_arg_error("function_name",
Pike_sp-
args,
args,
1,
+
bad_arg_error("function_name", args, 1,
"function", Pike_sp-args, "Destructed object.\n"); if(p == pike_trampoline_program) { struct pike_trampoline *t; t=((struct pike_trampoline *)func->u.object->storage); if(t->frame->current_object->prog) { p = t->frame->current_object->prog; f = t->func;
pike.git/src/builtin.cmod:1984:
add_ref(o); pop_n_elems(args); push_object(o); return; } SET_SVAL(*func, T_OBJECT, 0, object, func->u.object); return; default:
-
SIMPLE_
BAD_
ARG_ERROR("function_object",1,"function");
+
SIMPLE_ARG_
TYPE_
ERROR("function_object",1,"function");
} pop_n_elems(args); push_int(0); } /*! @decl program function_program(function|program f) *! *! Return the program the function @[f] is in. *! *! If @[f] is a global function defined in the runtime @expr{0@}
pike.git/src/builtin.cmod:2038:
} if (p) { ref_push_program(p); stack_pop_n_elems_keep_top(args); return; } } break; default:
-
SIMPLE_
BAD_
ARG_ERROR("function_program", 1, "function");
+
SIMPLE_ARG_
TYPE_
ERROR("function_program", 1, "function");
} pop_n_elems(args); push_int(0); }
-
+
/*! @class RandomInterface
+
*/
+
PIKECLASS RandomInterface
+
{
+
CVAR UINT64 int_buffer;
+
CVAR int buffer_bits;
-
/*!
@decl
mixed
random(object
o)
-
*!
If
random
is
called
with
an
object,
@[lfun::random]
will
be
-
*!
called in the object
.
+
#ifdef
PIKE_NULL_IS_SPECIAL
+
INIT
+
{
+
THIS->int_buffer
=
0;
+
THIS->buffer_bits
=
0;
+
}
+
#endif
+
+
/
*!
@decl
string(8bit)
random_string(int(0
.
.))
*!
-
*!
@seealso
-
*!
@[lfun::_random()]
+
*!
Prototype for the randomness generating function.
+
*!
+
*! Override this symbol to implement a usable class.
*/
-
+
PIKEFUN string(8bit) random_string(int(0..))
+
prototype;
+
{}
-
PMOD_EXPORT
-
PIKEFUN
mixed
random(object
o)
-
efun;
-
optflags OPT
_
TRY
_
OPTIMIZE|OPT_EXTERNAL_DEPEND;
+
static
void
fill
_
int
_
buffer()
{
-
int
f
=
low
_
find_lfun
(
o->prog, LFUN
__
RANDOM
);
-
if (
f
<
0)
{
-
Pike_error("
Calling
undefined
lfun::%s
.\n"
,
lfun
_
names
[
LFUN
__
RANDOM
]);
+
push_
int
(8);
+
apply
_
current(f
_
RandomInterface_random_string_fun_num
,
1
);
+
if
(
TYPEOF
(
Pike_sp[-1])
!=
T_STRING
||
+
Pike_
sp[-1].u.string->len != 8 )
+
Pike_
error("
Illegal
return
value from random_string
.\n"
);
+
#if
PIKE
_
BYTEORDER == 1234
+
/* Little endian. */
+
THIS->int_buffer = ((INT64 *)Pike_sp
[
-1].u.string->str)[0];
+
#else
+
/* Big endian. */
+
{
+
int i;
+
for (i = 0; i < 8; i++) {
+
((p
_
wchar0 *)&THIS->int
_
buffer)[i
]
= STR0(Pike_sp[-1].u.string
)
[7-i]
;
}
-
apply_low(o,
f,
0);
-
stack
_
swap()
;
+
}
+
#endif
+
THIS->buffer
_
bits = 64
;
pop_stack(); }
-
+
/* Generates a number 0<=c<limit from random bits taken from the
+
int_buffer. Follows the NIST SP800-90A method for converting bit
+
sequences into bound numbers, described in section B.5.1.1, and
+
summarized as "throw away attempts that are too large". */
+
static INT_TYPE read_int(INT_TYPE limit)
+
{
+
int bits;
+
UINT64 mask;
+
int i;
+
+
if(limit <= 1) return 0;
+
+
bits = my_log2(limit-1)+1;
+
mask = (((UINT64)1)<<bits)-1;
+
for(i=0; i<1000; i++)
+
{
+
INT_TYPE ret;
+
if(THIS->buffer_bits < bits)
+
fill_int_buffer();
+
ret = THIS->int_buffer & mask;
+
THIS->int_buffer >>= bits;
+
THIS->buffer_bits -= bits;
+
if( ret < limit )
+
return ret;
+
}
+
Pike_error("Failed to generate random data.\n");
+
}
+
/*! @decl int random(int max)
-
*! @decl float random(float max)
+
*!
-
*! This function returns a random number in the range
0
-
@[max]-
1
.
+
*! This function returns a random number in the range
+
*! @expr{0 ..
@[max]-
1@}
.
*! *! @seealso
-
*! @[
random_seed()
]
+
*! @[
Random
]
*/
-
-
PMOD_EXPORT
-
PIKEFUN int random(int
i
)
+
PIKEFUN int
(0..)
random(int
limit
)
{
-
if(i
<=
0)
RETURN
0;
-
#if SIZEOF
_
INT_TYPE > 4
-
if
(
i >> 31
)
{
-
unsigned INT_TYPE a = my_rand()
;
-
unsigned INT_TYPE b = my_rand();
-
RETURN (INT_TYPE)(((a<<32)|b) % i);
+
RETURN
read
_
int
(
limit
);
}
-
#endif
-
RETURN my_rand() % i;
-
}
+
-
PMOD_EXPORT
+
/*! @decl float random(float max)
+
*!
+
*! This function returns a random number in the range
+
*! @expr{0 .. @[max]-É›@}.
+
*!
+
*! @seealso
+
*! @[Random]
+
*/
PIKEFUN float random(float f) {
-
+
UINT64 value;
if(f<=0.0) RETURN 0.0;
-
#define
N
1048576
-
RETURN
f
*
(my
_
rand
()
%N/((float)N)) +
-
f
*
(my
_
rand()%N/(
((float)N)
*
((float)N)
))
;
+
if (THIS->buffer_bits < 64)
+
fill
_
int_buffer
()
;
+
value
=
THIS->int
_
buffer;
+
THIS->buffer_bits = 0
;
-
+
RETURN (FLOAT_TYPE)ldexp((double)f * value, -64);
} /*! @decl mixed random(array|multiset x) *! Returns a random element from @[x].
-
+
*!
+
*! @throws
+
*! Throws an exception if the array or multiset is empty.
*/
-
PMOD_EXPORT
+
PIKEFUN mixed random(array a) rawtype tFunc(tArr(tSetvar(0,tMix)),tVar(0)); { if(!a->size)
-
SIMPLE_
BAD_
ARG_ERROR("random", 1, "array with elements in it");
-
push_svalue(a->item + (
my
_
rand
(
) %
a->size))
;
-
stack_swap(
);
-
pop_stack();
+
SIMPLE_ARG_
TYPE_
ERROR("random", 1, "array with elements in it");
+
push_svalue(a->item + (
read
_
int
(a->size)));
}
-
PMOD_EXPORT
+
PIKEFUN mixed random(multiset m) rawtype tFunc(tSet(tSetvar(1,tMix)),tVar(1)); { if(multiset_is_empty (m))
-
SIMPLE_
BAD_
ARG_ERROR("random", 1, "multiset with elements in it");
-
if
(
multiset_
indval
(m
))
{
-
ptrdiff_t nodepos =
multiset_get_nth (m,
my
_
rand
(
) %
multiset_sizeof (m))
;
-
push_multiset_index (m, nodepos
)
;
-
push_multiset_value (m, nodepos
);
+
SIMPLE_ARG_
TYPE_
ERROR("random", 1, "multiset with elements in it");
+
push_
multiset_
index
(m
,
multiset_get_nth (m,
read
_
int
(multiset_sizeof (m))));
sub_msnode_ref (m);
-
f_aggregate (2);
+
}
-
else {
-
push_multiset_index (m, multiset_get_nth (m, my_rand() %
-
multiset_sizeof (m)));
-
sub_msnode_ref (m);
-
}
-
stack_swap();
-
pop_stack();
-
}
+
/*! @decl array random(mapping m) *! Returns a random index-value pair from the mapping.
-
+
*!
+
*! @array
+
*! @elem mixed 0
+
*! The index of the mapping entry.
+
*! @elem mixed 1
+
*! The value f the mapping entry.
+
*! @endarray
+
*!
+
*! @throws
+
*! Throws an exception if the mapping is empty.
*/
-
-
PMOD_EXPORT
+
PIKEFUN array random(mapping m) {
-
struct mapping_data *md=m->data;
-
size_t bucket, count;
+
struct keypair *k;
-
+
int e, count;
if(!m_sizeof(m))
-
SIMPLE_
BAD_
ARG_ERROR("random", 1, "mapping with elements in it");
+
SIMPLE_ARG_
TYPE_
ERROR("random", 1, "mapping with elements in it");
-
/*
Find
a
random, nonempty bucket */
-
bucket
=
my
_
rand
(
)
% md->hashsize;
-
while
(
! md->hash[bucket]
)
-
if(++bucket > (size_t
)
md->hashsize)
-
bucket=0
;
+
count
=
read
_
int
(
m_sizeof
(
m
) );
-
/*
Count
entries in bucket */
-
count=0;
-
for
(
k=md
->
hash[bucket];k;k=k->next
)
count++;
-
-
/*
Select
a random entry in this bucket */
-
count
=
my_rand()
%
count;
-
k=md->hash[bucket];
-
while
(count--
>
0
)
k=k->next;
-
-
/*
Push
result
and
return
*/
+
NEW_MAPPING_LOOP
(
m
->
data
)
+
{
+
if
(count--
<
1
)
+
{
push_svalue(&k->ind); push_svalue(&k->val); f_aggregate(2);
-
stack_swap();
-
pop_stack()
;
+
return
;
}
-
+
}
-
+
UNREACHABLE(return);
+
}
+
+
/*! @decl mixed random(object o)
+
*! If random is called with an object, @[lfun::_random] will be
+
*! called in the object.
+
*!
+
*! @throws
+
*! Throws an exception if the object doesn't have a _random method.
+
*!
+
*! @seealso
+
*! @[lfun::_random()]
+
*/
+
PIKEFUN mixed random(object o)
+
{
+
int f = low_find_lfun(o->prog, LFUN__RANDOM);
+
struct object *co;
+
+
if (f < 0)
+
Pike_error("Calling undefined lfun::%s.\n", lfun_names[LFUN__RANDOM]);
+
+
co = Pike_fp->current_object;
+
ref_push_function(co, f_RandomInterface_random_string_fun_num);
+
/* FIXME: precompiler doesn't generate usable fun_nums for variant
+
symbols. */
+
ref_push_function(co, find_shared_string_identifier(MK_STRING("random"),
+
co->prog));
+
apply_low(o, f, 2);
+
}
+
}
+
/*! @endclass
+
*/
+
+
/**
+
* Generates a random string of length len, using the current
+
* random_string() function, and pushes it on the stack.
+
*/
+
PMOD_EXPORT void push_random_string(unsigned len)
+
{
+
struct svalue *random =
+
simple_mapping_string_lookup(get_builtin_constants(), "random_string");
+
if(!random || (TYPEOF(*random) != T_FUNCTION))
+
Pike_error("Unable to resolve random function.\n");
+
push_int(len);
+
apply_svalue(random, 1);
+
if(TYPEOF(Pike_sp[-1])!=T_STRING || Pike_sp[-1].u.string->len != (ptrdiff_t)len ||
+
Pike_sp[-1].u.string->size_shift != 0)
+
Pike_error("Couldn't generate random string.\n");
+
}
+
+
#ifdef __NT__
+
#include <wincrypt.h>
+
static HCRYPTPROV crypto_handle;
+
#else
+
static int random_fd = -1;
+
#endif
+
/*! @class RandomSystem
+
*/
+
PIKECLASS RandomSystem
+
{
+
/*! @decl inherit RandomInterface
+
*/
+
INHERIT RandomInterface;
+
+
/*! @decl string(8bit) random_string(int(0..) len)
+
*!
+
*! Return a string of random data from the system randomness pool.
+
*!
+
*! On POSIX platforms this reads random data from @tt{/dev/urandom@}
+
*! on other platforms it may use other methods.
+
*!
+
*! @throws
+
*! May throw errors on unexpected state.
+
*/
+
PIKEFUN string(8bit) random_string(int(0..) len)
+
{
+
struct pike_string *ret;
+
char *str;
+
+
if( !len )
+
REF_RETURN empty_pike_string;
+
if( len<0 )
+
Pike_error("Bad argument 1 to random_string(). Expected int(0..).\n");
+
+
#ifdef __NT__
+
if(!crypto_handle)
+
{
+
if( !CryptAcquireContext(&crypto_handle, 0, 0, PROV_RSA_FULL,
+
CRYPT_VERIFYCONTEXT|CRYPT_SILENT) )
+
Pike_error("Failed to set up Crypto Service.\n");
+
}
+
+
ret = begin_shared_string(len);
+
str = ret->str;
+
if( !CryptGenRandom(crypto_handle, len, (BYTE*)str) )
+
{
+
do_free_unlinked_pike_string (ret);
+
Pike_error("Failed to create random data.\n");
+
}
+
#else /* !__NT__ */
+
while( random_fd == -1 )
+
{
+
random_fd = open("/dev/urandom", O_RDONLY);
+
if( random_fd==-1 ) {
+
if (errno == EINTR) continue; /* Retry */
+
Pike_error("Failed to open /dev/urandom.\n");
+
}
+
}
+
+
ret = begin_shared_string(len);
+
str = ret->str;
+
while( len )
+
{
+
int sz = read(random_fd, str, len);
+
if (sz < 0) {
+
if (errno == EINTR) continue; /* Retry */
+
+
free_string(ret);
+
+
/* Attempt to recover on next call. */
+
close(random_fd);
+
random_fd = -1;
+
+
Pike_error("Failed to read %d bytes from /dev/urandom.\n", len);
+
}
+
str += sz;
+
len -= sz;
+
}
+
#endif /* !__NT__ */
+
+
RETURN end_shared_string(ret);
+
}
+
}
+
/*! @endclass
+
*/
+
#if defined(HAVE_SETENV) && defined(HAVE_UNSETENV) #define USE_SETENV #else /* Used to hold refs to the strings that we feed to putenv. Indexed on * variable names, values are the "name=value" strings. * * This is not needed when using {,un}setenv(), since they maintain * their own corresponding table. */ static struct mapping *env_allocs = NULL; #endif
pike.git/src/builtin.cmod:2209:
pop_stack(); push_int (0); } else { char *entry = getenv (var->str); pop_stack(); if (!entry) push_int (0); else {
-
char *eq =
STRCHR
(entry, '=');
+
char *eq =
strchr
(entry, '=');
/* There should always be a '=' in the entry, but you never know.. */ push_string (make_shared_string (eq ? eq + 1 : entry)); } } } else { #ifdef DECLARE_ENVIRON extern char **environ; #endif
pike.git/src/builtin.cmod:2237:
* one in gnu libc). */ for (n = 0; environ[n]; n++) {} m = allocate_mapping (n); #ifndef USE_SETENV if (env_allocs) new_env_allocs = allocate_mapping (m_sizeof (env_allocs)); #endif /* !USE_SETENV */ while (--n >= 0) {
-
char *entry = environ[n], *eq =
STRCHR
(entry, '=');
+
char *entry = environ[n], *eq =
strchr
(entry, '=');
if (eq) { /* gnu libc getenv ignores variables without '='. */ struct pike_string *var = make_shared_binary_string (entry, eq - entry); struct pike_string *val = make_shared_string (eq + 1); mapping_string_insert_string (m, var, val); #ifndef USE_SETENV /* Populate new_env_allocs with the env_allocs entries that * are still in use. */ if (env_allocs) { struct svalue *ea_val = low_mapping_string_lookup (env_allocs, var);
pike.git/src/builtin.cmod:2280:
* updates the real environment. Everyone should use the version in * the master instead so that the cache doesn't get stale. */ PIKEFUN void _putenv (string var, void|string val) { #ifndef USE_SETENV struct pike_string *putenv_str, *env_alloc_var; #endif if (var->size_shift) SIMPLE_ARG_TYPE_ERROR ("putenv", 1, "string(0..255)");
-
if (string_has_null (var) ||
STRCHR
(var->str, '='))
+
if (string_has_null (var) ||
strchr
(var->str, '='))
SIMPLE_ARG_ERROR ("putenv", 1, "Variable name cannot contain '=' or NUL."); if (val) { #ifndef USE_SETENV struct string_builder sb; #endif if (val->size_shift) SIMPLE_ARG_TYPE_ERROR ("putenv", 2, "void|string(0..255)"); if (string_has_null (val))
pike.git/src/builtin.cmod:2362:
* assume no other entities are naughty enough to modify it). */ mapping_string_insert_string (env_allocs, env_alloc_var, putenv_str); else { struct svalue key; SET_SVAL(key, T_STRING, 0, string, env_alloc_var); map_delete (env_allocs, &key); } #endif /* !USE_SETENV */ }
-
#if defined(PIKE_DEBUG) && defined(PIKE_PORTABLE_BYTECODE)
-
-
/*! @decl void disassemble(function fun)
-
*! @belongs Debug
-
*!
-
*! Disassemble a Pike function to @[Stdio.stderr].
-
*!
-
*! @note
-
*! This function is only available if the Pike runtime
-
*! has been compiled with debug enabled.
-
*/
-
PIKEFUN void _disassemble(function fun)
-
{
-
if ((TYPEOF(*fun) != T_FUNCTION) ||
-
(SUBTYPEOF(*fun) == FUNCTION_BUILTIN)) {
-
fprintf(stderr,
-
"Disassembly only supported for functions implemented in Pike.\n");
-
} else if (!fun->u.object->prog) {
-
fprintf(stderr, "Function in destructed object.\n");
-
} else {
-
int f = SUBTYPEOF(*fun);
-
struct reference *ptr = PTR_FROM_INT(fun->u.object->prog, f);
-
struct program *p = PROG_FROM_PTR(fun->u.object->prog, ptr);
-
struct identifier *id = p->identifiers + ptr->identifier_offset;
-
if (id->func.offset >= 0) {
-
struct pike_string *tripples =
-
p->strings[read_program_data(p->program + id->func.offset, -1)];
-
switch(tripples->size_shift) {
-
#define CASE(SHIFT) \
-
case SHIFT: \
-
{ \
-
PIKE_CONCAT(p_wchar, SHIFT) *str = \
-
PIKE_CONCAT(STR, SHIFT)(tripples); \
-
int i=0; \
-
while(i < tripples->len) { \
-
fprintf(stderr, "@@@ %d: %s, %d, %d\n", \
-
i/3, \
-
instrs[*str - F_OFFSET]. \
-
name, \
-
str[1], str[2]); \
-
str += 3; \
-
i += 3; \
-
} \
-
} \
-
break
-
CASE(0);
-
CASE(1);
-
CASE(2);
-
#undef CASE
-
}
-
} else {
-
fprintf(stderr, "Prototype.\n");
-
}
-
}
-
pop_n_elems(args);
-
push_int(0);
-
}
-
-
#endif /* PIKE_DEBUG && PIKE_PORTABLE_BYTECODE */
-
+
/* * Backtrace handling. */ /*! @module Pike */ /*! @class BacktraceFrame */
pike.git/src/builtin.cmod:2446:
PIKEVAR program oprog flags ID_PROTECTED|ID_PRIVATE; #endif PIKEVAR array args; /* These are cleared when filename and lineno have been initialized * from them. */ PIKEVAR program prog flags ID_PROTECTED|ID_PRIVATE; CVAR PIKE_OPCODE_T *pc; /* These two are considered to be uninitialized from prog, pc and
-
* fun as long as lineno ==
-1
. */
+
* fun as long as lineno ==
0
. */
CVAR struct pike_string *filename; CVAR INT_TYPE lineno;
-
+
#ifdef PIKE_NULL_IS_SPECIAL
INIT { THIS->pc = NULL;
-
THIS->lineno =
-1
;
+
THIS->lineno =
0
;
THIS->filename = NULL; }
-
+
#endif
EXIT gc_trivial; { if (THIS->filename) { free_string(THIS->filename); THIS->filename = NULL; } THIS->pc = NULL;
-
THIS->lineno =
-1
;
+
THIS->lineno =
0
;
} /* NOTE: Use old-style getter/setter syntax for compatibility with * old Parser.Pike.split() used by precompile.pike. */ PIKEFUN mixed `->fun() { push_svalue(&THIS->_fun); }
pike.git/src/builtin.cmod:2496:
} #endif assign_svalue(&THIS->_fun, val); } /*! @decl int(0..1) _is_type(string t) *! This object claims to be an array for backward compatibility. */ PIKEFUN int(0..1) _is_type(string t) {
-
INT_TYPE
res =
(t ==
findstring("
array
"));
-
pop
_
n_elems(args
);
-
push_int(res);
+
RETURN
(t ==
literal_
array_
string
);
} static void fill_in_file_and_line() { struct pike_string *file = NULL;
-
assert (THIS->lineno ==
-1
);
+
assert (THIS->lineno ==
0
);
if (THIS->pc && THIS->prog) { file = low_get_line(THIS->pc, THIS->prog, &THIS->lineno); THIS->pc = NULL; } else if (TYPEOF(THIS->_fun) == PIKE_T_FUNCTION) { #ifdef PIKE_DEBUG if (THIS->_fun.u.object->prog && THIS->_fun.u.object->prog != THIS->oprog) { struct identifier *id = ID_FROM_INT(THIS->oprog, SUBTYPEOF(THIS->_fun));
pike.git/src/builtin.cmod:2541:
if (THIS->prog) { free_program(THIS->prog); THIS->prog = NULL; } } /*! @decl string _sprintf(int c, mapping|void opts) */ PIKEFUN string _sprintf(int c, mapping|void opts)
+
flags ID_PROTECTED;
{ pop_n_elems(args); if (c != 'O') { push_undefined (); return; }
-
push_text("backtrace_frame(");
+
push_
static_
text("backtrace_frame(");
-
if (THIS->lineno ==
-1
) fill_in_file_and_line();
+
if (THIS->lineno ==
0
) fill_in_file_and_line();
if (THIS->filename) { ref_push_string(THIS->filename);
-
push_text(":");
+
push_
static_
text(":");
push_int(THIS->lineno);
-
push_text(", ");
+
push_
static_
text(", ");
f_add(4); } else {
-
push_text("Unknown file, ");
+
push_
static_
text("Unknown file, ");
} if (TYPEOF(THIS->_fun) == PIKE_T_FUNCTION) { if (THIS->_fun.u.object->prog) { #ifdef PIKE_DEBUG if (THIS->_fun.u.object->prog != THIS->oprog) { struct identifier *id = ID_FROM_INT(THIS->oprog, SUBTYPEOF(THIS->_fun)); /* FIXME: Dump dmalloc info for the object? */ Pike_fatal("Lost track of function pointer! Function name was %s.\n", id->name?id->name->str:"<no name>"); } #endif push_svalue(&THIS->_fun); f_function_name(1);
-
push_text("(), ");
+
push_
static_
text("(), ");
f_add(2); } else { free_svalue(&THIS->_fun); SET_SVAL(THIS->_fun, PIKE_T_INT, NUMBER_DESTRUCTED, integer, 0);
-
push_text("destructed_function(), ");
+
push_
static_
text("destructed_function(), ");
} } else if (TYPEOF(THIS->_fun) == PIKE_T_PROGRAM) { /* FIXME: Use the master? */
-
push_text("program(), ");
+
push_
static_
text("program(), ");
} else if (TYPEOF(THIS->_fun) == PIKE_T_STRING) { push_svalue(&THIS->_fun);
-
push_text("(), ");
+
push_
static_
text("(), ");
f_add(2); } else {
-
push_text("destructed_function(), ");
+
push_
static_
text("destructed_function(), ");
} if (THIS->args) {
-
push_text("Args: ");
+
push_
static_
text("Args: ");
push_int(THIS->args->size); f_add(2); } else {
-
push_text("No args");
+
push_
static_
text("No args");
}
-
push_text(")");
+
push_
static_
text(")");
f_add(5); } /*! @decl int(3..) _sizeof() */ PIKEFUN int(3..) _sizeof()
-
+
flags ID_PROTECTED;
{ if (THIS->args) { push_int(THIS->args->size + 3); } else { push_int(3); } } /*! @decl mixed `[](int index, int|void end_or_none) *! The BacktraceFrame object can be indexed as an array. */ PIKEFUN mixed `[](int index, int|void end_or_none)
-
+
flags ID_PROTECTED;
{ INT_TYPE end = index;
-
INT32 numargs =
0
;
+
INT32 numargs =
3
;
INT32 i;
-
if (THIS->args)
{
-
numargs = THIS->args->size;
-
}
+
if (THIS->args)
+
numargs
+
= THIS->args->size;
-
numargs += 3;
-
+
if (!end_or_none) {
-
if (index < 0)
{
-
index_error("pike_frame->`[]",
Pike_sp-
args,
args,
NULL, Pike_sp-args,
+
if (index < 0)
+
index_error("pike_frame->`[]", args, NULL, Pike_sp-args,
"Indexing with negative index (%"PRINTPIKEINT"d)\n", index);
-
}
else if (index >= numargs)
{
-
index_error("pike_frame->`[]",
Pike_sp-
args,
args,
NULL, Pike_sp-args,
+
else if (index >= numargs)
+
index_error("pike_frame->`[]", args, NULL, Pike_sp-args,
"Indexing with too large index (%"PRINTPIKEINT"d)\n", index);
-
}
-
}
else
{
-
if (TYPEOF(*end_or_none) != PIKE_T_INT) {
-
SIMPLE_BAD_ARG_ERROR("`[]",2,"int|void");
-
}
+
} else
end = end_or_none->u.integer;
-
}
+
pop_n_elems(args); if (end_or_none) { if ((end < 0) || (end < index) || (index >= numargs)) { f_aggregate(0); return; }
-
if (end >= numargs)
{
+
if (end >= numargs)
end = numargs-1; }
-
}
+
for (i = index; i <= end; i++) { switch(i) { case 0: /* Filename */
-
if (THIS->lineno ==
-1
) fill_in_file_and_line();
-
if (THIS->filename)
{
+
if (THIS->lineno ==
0
) fill_in_file_and_line();
+
if (THIS->filename)
ref_push_string(THIS->filename);
-
}
else
{
+
else
push_int(0);
-
}
+
break; case 1: /* Linenumber */
-
if (THIS->lineno ==
-1
) fill_in_file_and_line();
+
if (THIS->lineno ==
0
) fill_in_file_and_line();
push_int(THIS->lineno); break; case 2: /* Function */ push_svalue(&THIS->_fun); break; default: /* Arguments */ { if ((i > 2) && (THIS->args) && (i-3 < THIS->args->size)) { push_svalue(THIS->args->item + (i - 3)); break; }
-
bad_arg_error("
backtrace_frame->
`[]",
Pike_sp-
args,
args,
1,
+
bad_arg_error("`[]", args, 1,
"int(0..)", Pike_sp-args, "Bad argument 1 to backtrace_frame->`[](): " "Expected int(0..%d)\n", numargs + 2); }
-
/* NOT_REACHED */
-
break;
+
UNREACHABLE(
break
)
;
} }
-
if (end_or_none)
{
+
if (end_or_none)
f_aggregate(1 + end - index); }
-
}
+
/*! @decl mixed `[]=(int index, mixed value) */ PIKEFUN mixed `[]=(int index, mixed value)
-
+
flags ID_PROTECTED;
{
-
INT32 numargs =
0
;
+
INT32 numargs =
3
;
-
if (THIS->args)
{
-
numargs = THIS->args->size;
-
}
+
if (THIS->args)
+
numargs
+
= THIS->args->size;
-
numargs += 3;
-
-
if ((index < -numargs) || (index >= numargs))
{
-
index_error("pike_frame->`[]=",
Pike_sp-
args,
args,
NULL, Pike_sp-args,
+
if ((index < -numargs) || (index >= numargs))
+
index_error("pike_frame->`[]=", args, NULL, Pike_sp-args,
"Index %"PRINTPIKEINT"d is out of array range 0..%d,\n", index, numargs-1);
-
}
else if (index < 0)
{
+
else if (index < 0)
index += numargs;
-
}
+
if (args > 2) { pop_n_elems(args - 2); args = 2; } switch(index) { case 0: /* Filename */
-
if (THIS->lineno ==
-1
) fill_in_file_and_line();
+
if (THIS->lineno ==
0
) fill_in_file_and_line();
if (TYPEOF(*value) != PIKE_T_STRING) { if ((TYPEOF(*value) != PIKE_T_INT) || (value->u.integer)) {
-
SIMPLE_
BAD_
ARG_ERROR("
backtrace_frame->
`[]=", 2,
-
"string|int(0..0)");
+
SIMPLE_ARG_
TYPE_
ERROR("`[]=", 2, "string|int(0..0)");
} if (THIS->filename) { free_string(THIS->filename); THIS->filename = NULL; } } else { if (THIS->filename) { free_string(THIS->filename); THIS->filename = NULL; } copy_shared_string(THIS->filename, value->u.string); } break; case 1: /* Linenumber */
-
if (THIS->lineno ==
-1
) fill_in_file_and_line();
-
if (TYPEOF(*value) != PIKE_T_INT)
{
-
SIMPLE_
BAD_
ARG_ERROR("
backtrace_frame->
`[]=", 2, "int(1..)");
-
}
+
if (THIS->lineno ==
0
) fill_in_file_and_line();
+
if (TYPEOF(*value) != PIKE_T_INT)
+
SIMPLE_ARG_
TYPE_
ERROR("`[]=", 2, "int(1..)");
THIS->lineno = value->u.integer; break; case 2: /* Function */
-
if (THIS->lineno ==
-1
) fill_in_file_and_line();
+
if (THIS->lineno ==
0
) fill_in_file_and_line();
assign_svalue(&THIS->_fun, value); break; default: /* Arguments */ assign_svalue(THIS->args->item + index - 3, value); break; } stack_swap(); pop_stack(); }
pike.git/src/builtin.cmod:2787:
*! the Pike interpreter. *! @member int "abi" *! The number of bits in the ABI. Usually @expr{32@} or @expr{64@}. *! @member int "native_byteorder" *! The byte order used by the native cpu. *! Usually @expr{1234@} (aka little endian) or *! @expr{4321@} (aka bigendian). *! @member int "int_size" *! The number of bits in the native integer type. *! Usually @expr{32@} or @expr{64@}.
+
*! @member int "time_size"
+
*! The number of bits in the native @tt{time_t@} type.
+
*! This is typically the same value as @expr{"int_size"@}.
*! @member int "float_size" *! The number of bits in the native floating point type. *! Usually @expr{32@} or @expr{64@}.
-
*! @member int(
0
..1) "auto_bignum"
-
*!
Present
if integers
larger than the native size are
automatically
-
*! converted into bignums.
+
*! @member int(
1
..1) "auto_bignum"
+
*!
Integers
larger than the native size are
now always
+
*!
automatically
converted into bignums.
*! @endmapping */ PIKEFUN mapping(string:int|string) get_runtime_info() optflags OPT_TRY_OPTIMIZE; { pop_n_elems(args);
-
push_
constant
_text("bytecode_method");
-
push_
constant_
text(PIKE_BYTECODE_METHOD_NAME);
-
push_
constant
_text("abi");
+
push_
static
_text("bytecode_method");
+
push_text(PIKE_BYTECODE_METHOD_NAME);
+
push_
static
_text("abi");
push_int(sizeof(void *) * 8);
-
push_
constant
_text("native_byteorder");
+
push_
static
_text("native_byteorder");
push_int(PIKE_BYTEORDER);
-
push_
constant
_text("int_size");
+
push_
static
_text("int_size");
push_int(sizeof(INT_TYPE) * 8);
-
push_
constant
_text("float_size");
+
push_
static
_text("
time_size");
+
push_int(sizeof(time_t) * 8);
+
push_static_text("
float_size");
push_int(sizeof(FLOAT_TYPE) * 8);
-
push_
constant
_text("auto_bignum");
+
push_
static
_text("auto_bignum");
push_int(1);
-
f_aggregate_mapping(
6
*2);
+
f_aggregate_mapping(
7
*2);
} /*! @endmodule */ void low_backtrace(struct Pike_interpreter_struct *i) { struct svalue *stack_top = i->stack_pointer; struct pike_frame *f, *of = 0; int size = 0; struct array *res = NULL; for (f = i->frame_pointer; f; f = f->next) { size++; } res = allocate_array_no_init(size, 0); push_array(res); for (f = i->frame_pointer; f && size; f = (of = f)->next) {
-
struct object *o =
low
_clone(backtrace_frame_program);
+
struct object *o =
fast
_clone
_object
(backtrace_frame_program);
struct backtrace_frame_struct *bf; struct identifier *function = NULL;
-
call_c_initializers(o);
-
+
size--; SET_SVAL(res->item[size], PIKE_T_OBJECT, 0, object, o); bf = OBJ2_BACKTRACE_FRAME(o);
-
+
SET_SVAL(bf->_fun, PIKE_T_INT, NUMBER_DESTRUCTED, integer, 0);
+
+
if (!f->context) {
+
if (f->pc == (void *)do_gc) {
+
SET_SVAL(bf->_fun, PIKE_T_STRING, 0, string, make_shared_string("gc"));
+
}
+
continue;
+
}
+
if ((bf->prog = f->context->prog)) { add_ref(bf->prog); bf->pc = f->pc; }
-
SET_SVAL(bf->_fun, PIKE_T_INT, NUMBER_DESTRUCTED, integer, 0);
-
+
if (f->current_object && f->current_object->prog) { if (f->fun == FUNCTION_BUILTIN) { /* Unusual case. The frame is from call_c_initializers(), gc() * or similar. cf [bug 6156]. /grubba * * Masquerade as the program. * * FIXME: Ought to keep parent-pointers. */ SET_SVAL(bf->_fun, PIKE_T_PROGRAM, 0,
pike.git/src/builtin.cmod:2876:
object, f->current_object); add_ref(f->current_object); function = ID_FROM_INT(f->current_object->prog, f->fun); #ifdef PIKE_DEBUG add_ref(bf->oprog = bf->_fun.u.object->prog); #endif } } if (f->locals) {
-
INT32 numargs =
DO_NOT_WARN
(
(
INT32) MINIMUM(f->num_args,
-
stack_top - f->locals)
)
;
+
INT32 numargs = (INT32) MINIMUM(f->num_args,
+
stack_top - f->locals);
INT32 varargs = 0; if(of && of->locals) { /* f->num_args can be too large, so this is necessary for some * reason. I don't know why. /mast * * possibly because f->num_args was uninitialized for c_initializers * /arne * */
-
numargs =
DO_NOT_WARN
(
(
INT32)MINIMUM(f->num_args,of->locals - f->locals)
)
;
+
numargs = (INT32)MINIMUM(f->num_args,of->locals - f->locals);
} numargs = MAXIMUM(numargs, 0); /* Handle varargs... */ if (function && (function->identifier_flags & IDENTIFIER_VARARGS) && (f->locals + numargs < stack_top) && (TYPEOF(f->locals[numargs]) == T_ARRAY)) { varargs = f->locals[numargs].u.array->size; }
pike.git/src/builtin.cmod:2942:
*! @elem function fun *! The function that was called at this level. *! @elem mixed|void ... args *! The arguments that the function was called with. *! @endarray *! *! The current call frame will be last in the array. *! *! @note *! Please note that the frame order may be reversed in a later version
-
*!
(than 7.1)
of Pike to accommodate for deferred backtraces.
+
*! of Pike to accommodate for deferred backtraces.
*! *! Note that the arguments reported in the backtrace are the current *! values of the variables, and not the ones that were at call-time. *! This can be used to hide sensitive information from backtraces *! (eg passwords). *! *! @seealso *! @[catch()], @[throw()] */ PMOD_EXPORT PIKEFUN array(mixed) backtrace() efun; optflags OPT_EXTERNAL_DEPEND; { low_backtrace(& Pike_interpreter); }
-
/*! @module String
-
*/
-
-
/*! @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;
-
}
-
-
/*! @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_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 )
-
{
-
struct pike_string *string_t;
-
struct pike_string *int_t;
-
MAKE_CONST_STRING( string_t, "string" );
-
MAKE_CONST_STRING( int_t, "int" );
-
-
if( type == string_t )
-
{
-
pop_n_elems( args );
-
if( Pike_fp->current_object->refs != 1 )
-
f_Buffer_get_copy( 0 );
-
else
-
f_Buffer_get( 0 );
-
return;
-
}
-
-
if( type == int_t )
-
{
-
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;
-
}
-
Pike_error("Cannot cast to %S\n", type);
-
}
-
-
/*! @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);
-
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.
-
*!
-
*! @seealso
-
*! @[addat()]
-
*/
-
PIKEFUN int add( string|Buffer ... arg1 )
-
rawtype tFuncV(tNone, tOr(tString, tObjIs_BUFFER), tIntPos);
-
{
-
struct Buffer_struct *str = THIS;
-
int init_from_arg0 = 0, j;
-
-
for (j=0; j < args; j++) {
-
if (TYPEOF(Pike_sp[j-args]) == PIKE_T_STRING) {
-
} else if ((TYPEOF(Pike_sp[j-args]) != PIKE_T_OBJECT) ||
-
(Pike_sp[j-args].u.object->prog != Buffer_program)) {
-
SIMPLE_BAD_ARG_ERROR("add", j+1, "string|String.Buffer");
-
}
-
}
-
-
if (!str->str.s && args) {
-
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 {
-
a = OBJ2_BUFFER(Pike_sp[j-args].u.object)->str.s;
-
if (!a) continue;
-
}
-
sum += a->len;
-
shift |= a->size_shift;
-
}
-
if (sum < str->initial)
-
sum = str->initial;
-
else if (sum > str->initial)
-
sum <<= 1;
-
shift = shift & ~(shift >> 1);
-
-
if ((TYPEOF(Pike_sp[-args]) == PIKE_T_STRING) &&
-
(shift == Pike_sp[-args].u.string->size_shift) &&
-
init_string_builder_with_string (&str->str, Pike_sp[-args].u.string)) {
-
mark_free_svalue (Pike_sp - args);
-
if (sum > str->str.s->len)
-
string_build_mkspace (&str->str, sum - str->str.s->len, shift);
-
init_from_arg0 = 1;
-
}
-
else
-
init_string_builder_alloc(&str->str, sum, shift);
-
-
/* We know it will be a string that really is this wide. */
-
str->str.known_shift = shift;
-
}
-
-
for( j = init_from_arg0; 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;
-
}
-
string_builder_shared_strcat( &str->str, a );
-
}
-
-
if (str->str.s) {
-
RETURN str->str.s->len;
-
} else {
-
RETURN 0;
-
}
-
}
-
-
/*! @decl int addat(int(0..) pos, string|String.Buffer ... data)
-
*!
-
*! Adds @[data] to the buffer, starting at position @[pos].
-
*!
-
*! @returns
-
*! Returns the size of the buffer.
-
*!
-
*! @note
-
*! If the buffer isn't of the required size, it will be padded
-
*! with NUL-characters.
-
*!
-
*! @note
-
*! Pike 7.8 and earlier did not support adding @[String.Buffer]s
-
*! directly.
-
*!
-
*! @seealso
-
*! @[add()]
-
*/
-
PIKEFUN int addat(int(0..) pos, string ... arg1 )
-
rawtype tFuncV(tNone, tOr(tString, tObjIs_BUFFER), tIntPos);
-
{
-
struct Buffer_struct *str = THIS;
-
-
if (pos < 0)
-
SIMPLE_BAD_ARG_ERROR("addat", 1, "int(0..)");
-
-
if (args) {
-
int init_from_arg0 = 0, j;
-
ptrdiff_t sum = 0;
-
int shift = 0;
-
for (j=1; 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_BAD_ARG_ERROR("addat", 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;
-
}
-
-
if (!str->str.s) {
-
if ((sum + pos) <= str->initial) {
-
sum = str->initial;
-
} else {
-
sum <<= 1;
-
sum += pos;
-
}
-
shift = shift & ~(shift >> 1);
-
-
init_string_builder_alloc(&str->str, sum, shift);
-
} else {
-
sum += pos;
-
shift |= str->str.known_shift;
-
shift = shift & ~(shift >> 1);
-
if (sum > str->str.s->len) {
-
string_build_mkspace(&str->str, sum - str->str.s->len, shift);
-
} else if (shift != str->str.known_shift) {
-
string_build_mkspace(&str->str, 0, shift);
-
}
-
}
-
/* We know it will be a string that really is this wide. */
-
str->str.known_shift = shift;
-
-
if (str->str.s->len < pos) {
-
/* Clear the padding. */
-
MEMSET(str->str.s->str + (str->str.s->len << str->str.s->size_shift),
-
0, (pos - str->str.s->len) << str->str.s->size_shift);
-
}
-
-
for(j = 1; 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, pos), a);
-
pos += a->len;
-
}
-
-
if (str->str.s->len < pos) {
-
str->str.s->len = pos;
-
/* Ensure NUL-termination */
-
str->str.s->str[str->str.s->len << str->str.s->size_shift] = 0;
-
}
-
}
-
-
if (str->str.s) {
-
RETURN str->str.s->len;
-
} else {
-
RETURN 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, 0, &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;
-
if( str )
-
{
-
ptrdiff_t len = str->len;
-
if( len > 0 )
-
{
-
char *d = (char *)str->str;
-
switch( str->size_shift )
-
{
-
case 0:
-
RETURN make_shared_binary_string0((p_wchar0 *)d,len);
-
break;
-
case 1:
-
RETURN make_shared_binary_string1((p_wchar1 *)d,len);
-
break;
-
case 2:
-
RETURN make_shared_binary_string2((p_wchar2 *)d,len);
-
break;
-
}
-
}
-
}
-
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;
-
if( str->str.s )
-
{
-
struct pike_string *s = finish_string_builder( &str->str );
-
str->str.malloced = 0;
-
str->str.s = NULL;
-
RETURN s;
-
}
-
pop_n_elems(args);
-
push_empty_string();
-
return;
-
}
-
-
/*! @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()
-
{
-
struct Buffer_struct *str = THIS;
-
RETURN str->str.s ? str->str.s->len : 0;
-
}
-
-
INIT
-
{
-
struct Buffer_struct *str = THIS;
-
MEMSET( str, 0, sizeof( *str ) );
-
}
-
-
EXIT
-
gc_trivial;
-
{
-
struct Buffer_struct *str = THIS;
-
if( str->str.s )
-
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. */
pike.git/src/builtin.cmod:3477:
/* NOTE: from and to are only kept for _encode()'s use. */ PIKEVAR array from flags ID_PROTECTED; PIKEVAR array to flags ID_PROTECTED; PIKEFUN int _size_object() { int res = 0, i; if( THIS->ctx.v ) { struct svalue tmp;
-
tmp
.type
=
PIKE_T_STRING;
+
SET_SVAL_TYPE(
tmp
,
PIKE_T_STRING
)
;
for( i=0; i<THIS->ctx.num; i++ ) { res += sizeof(struct replace_many_tupel); tmp.u.string = THIS->ctx.v[i].ind; res += rec_size_svalue( &tmp, NULL ); tmp.u.string = THIS->ctx.v[i].val; res += rec_size_svalue( &tmp, NULL ); } } RETURN res; }
-
/*! @decl void create(
array(string
)
|
mapping(string:string)
|void from, @
-
*!
array(string)|string
|void
to)
+
/*! @decl void create(
)
+
*! @decl void create
(mapping(string:string)
)
+
*!
@decl
void
create(array(string)
from,
array(string)|string to)
*/ PIKEFUN void create(array(string)|mapping(string:string)|void from_arg, array(string)|string|void to_arg) { if (THIS->from) { free_array(THIS->from); THIS->from = NULL; } if (THIS->to) { free_array(THIS->to); THIS->to = NULL; } if (THIS->ctx.v) free_replace_many_context(&THIS->ctx);
-
if (!args) {
-
push_int(0);
-
return;
-
}
-
if (from_arg && TYPEOF(*from_arg) == T_MAPPING) {
+
if (to_arg) {
-
Pike_error("Bad number of arguments to create().\n");
-
}
-
THIS->from = mapping_indices(from_arg->u.mapping);
-
THIS->to = mapping_values(from_arg->u.mapping);
-
pop_n_elems(args);
-
args = 0;
-
} else {
-
/* FIXME: Why is from declared |void, when it isn't allowed
-
* to be void?
-
* /grubba 2004-09-02
-
*
-
* It probably has to do with the "
if (!
args)" above: It should
-
* be possible to create an empty instance. /mast
-
*/
-
if (!
from_arg ||
!to_arg) {
-
Pike_error
(
"Bad number of arguments to create().\n");
-
}
-
pop_n_elems(args-2);
-
args = 2;
-
if (
TYPEOF(*from_arg) != T_ARRAY) {
-
SIMPLE_
BAD_
ARG_ERROR("
Replace
", 1,
+
if (!from_arg || (TYPEOF(*from_arg) != T_ARRAY)
)
{
+
SIMPLE_ARG_
TYPE_
ERROR("
replace
", 1,
"array(string)|mapping(string:string)"); } if (TYPEOF(*to_arg) == T_STRING) { push_int(from_arg->u.array->size); stack_swap(); f_allocate(2);
-
+
to_arg = Pike_sp - 1;
}
-
if (TYPEOF(*to_arg) != T_ARRAY) {
-
SIMPLE_
BAD_
ARG_ERROR("
Replace
", 2, "array(string)|string");
+
else
if (TYPEOF(*to_arg) != T_ARRAY) {
+
SIMPLE_ARG_
TYPE_
ERROR("
replace
", 2, "array(string)|string");
}
-
if (from_arg->u.array->size != to_arg->u.array->size) {
+
else
if (from_arg->u.array->size != to_arg->u.array->size) {
Pike_error("Replace must have equal-sized from and to arrays.\n"); } add_ref(THIS->from = from_arg->u.array); add_ref(THIS->to = to_arg->u.array);
-
+
} else if (from_arg) {
+
if (TYPEOF(*from_arg) != T_MAPPING)
+
Pike_error("Illegal arguments to create().\n");
+
THIS->from = mapping_indices(from_arg->u.mapping);
+
THIS->to = mapping_values(from_arg->u.mapping);
+
} else {
+
pop_n_elems(args);
+
return;
} if (!THIS->from->size) { /* Enter no-op mode. */ pop_n_elems(args);
-
push_int(0);
+
return; } if( (THIS->from->type_field & ~BIT_STRING) && (array_fix_type_field(THIS->from) & ~BIT_STRING) )
-
SIMPLE_
BAD_
ARG_ERROR("
Replace
", 1,
+
SIMPLE_ARG_
TYPE_
ERROR("
replace
", 1,
"array(string)|mapping(string:string)"); if( (THIS->to->type_field & ~BIT_STRING) && (array_fix_type_field(THIS->to) & ~BIT_STRING) )
-
SIMPLE_
BAD_
ARG_ERROR("
Replace
", 2, "array(string)|string");
+
SIMPLE_ARG_
TYPE_
ERROR("
replace
", 2, "array(string)|string");
compile_replace_many(&THIS->ctx, THIS->from, THIS->to, 1);
-
+
pop_n_elems(args);
-
push_int(0);
+
} /*! @decl string `()(string str) */ PIKEFUN string `()(string str) { if (!THIS->ctx.v) { /* The result is already on the stack in the correct place... */ return; }
pike.git/src/builtin.cmod:3608:
push_undefined(); } f_aggregate(2); } /*! @decl void _decode(array(array(string)) encoded) */ PIKEFUN void _decode(array(array(string)) encoded) { INT32 i;
-
for (i=0; i < encoded->size; i++)
{
+
for (i=0; i < encoded->size; i++)
push_svalue(encoded->item + i);
-
stack_swap();
-
}
-
pop_stack();
+
f_multi_string_replace_create(i); }
-
+
#ifdef PIKE_NULL_IS_SPECIAL
INIT {
-
MEMSET
(&THIS->ctx, 0, sizeof(struct replace_many_context));
+
memset
(&THIS->ctx, 0, sizeof(struct replace_many_context));
}
-
+
#endif
EXIT gc_trivial; { free_replace_many_context(&THIS->ctx); } } /*! @endclass */
pike.git/src/builtin.cmod:3650:
*! not be used manually. */ PIKECLASS single_string_replace { CVAR SearchMojt mojt; PIKEVAR string del flags ID_PROTECTED|ID_PRIVATE; PIKEVAR string to flags ID_PROTECTED|ID_PRIVATE; EXTRA {
-
MAP_VARIABLE ("o",
tObj, ID_PROTECTED|ID_PRIVATE,
+
PIKE_
MAP_VARIABLE ("o",
single_string_replace_storage_offset + OFFSETOF (single_string_replace_struct, mojt.container),
-
T_OBJECT);
+
tObj,
T_OBJECT
, ID_PROTECTED|ID_PRIVATE
);
} /*! @decl void create(string|void from, string|void to) *! *! @note *! May be called with either zero or two arguments. */ PIKEFUN void create(string|void del, string|void to) { if (THIS->del) { free_string(THIS->del); THIS->del = NULL; } if (THIS->to) { free_string(THIS->to); THIS->to = NULL; }
-
if (!del) return;
+
if (!del)
{
+
pop_n_elems(args);
+
return;
+
}
if (!to) {
-
SIMPLE_
BAD_
ARG_ERROR("
String.SingleReplace->create
", 2, "string");
+
SIMPLE_ARG_
TYPE_
ERROR("
replace
", 2, "string");
} if (del == to) { /* No-op... */
-
+
pop_n_elems(args);
return; } copy_shared_string(THIS->del, del); copy_shared_string(THIS->to, to); if (del->len) { THIS->mojt = simple_compile_memsearcher(del); }
-
+
pop_n_elems(args);
} /*** replace function ***/ typedef char *(* replace_searchfunc)(void *,void *,size_t); /*! @decl string `()(string str) */ PIKEFUN string `()(string str) { int shift;
pike.git/src/builtin.cmod:3731:
} else { char *s, *end, *tmp; replace_searchfunc f = (replace_searchfunc)0; void *mojt_data = THIS->mojt.data; PCHARP r; end = str->str+(str->len<<str->size_shift); switch(str->size_shift) {
-
case
0
: f = (replace_searchfunc)THIS->mojt.vtab->func0; break;
-
case
1
: f = (replace_searchfunc)THIS->mojt.vtab->func1; break;
-
case
2
: f = (replace_searchfunc)THIS->mojt.vtab->func2; break;
-
#ifdef
PIKE_DEBUG
-
default:
Pike_fatal
(
"Illegal shift.\n"
);
-
#endif
+
case
eightbit
: f = (replace_searchfunc)THIS->mojt.vtab->func0; break;
+
case
sixteenbit
: f = (replace_searchfunc)THIS->mojt.vtab->func1; break;
+
case
thirtytwobit
: f = (replace_searchfunc)THIS->mojt.vtab->func2; break;
+
default:
UNREACHABLE
(
break
);
} if(del->len == to->len) { ret = begin_wide_shared_string(str->len, shift); } else { INT32 delimiters = 0; s = str->str;
pike.git/src/builtin.cmod:3803:
} /*! @decl void _decode(array(string)|int(0..0) encoded) */ PIKEFUN void _decode(array(string)|int(0..0) encoded_) { INT32 i = 0; if (TYPEOF(*encoded_) == PIKE_T_ARRAY) { struct array *encoded = encoded_->u.array;
-
for (i=0; i < encoded->size; i++)
{
+
for (i=0; i < encoded->size; i++)
push_svalue(encoded->item + i);
-
stack_swap();
+
}
-
}
-
pop_stack();
+
f_single_string_replace_create(i); } } /*! @endclass */ /*! @class Bootstring *!
pike.git/src/builtin.cmod:3920:
i %= output.s->len+1; string_builder_putchar( &output, n ); if (i != output.s->len-1) switch (output.s->size_shift) { case 0: { p_wchar0 *s = STR0(output.s); INT_TYPE p = output.s->len; while (--p>i) s[p] = s[p-1];
-
s[p] =
DO_NOT_WARN
(
(
p_wchar0) n
)
;
+
s[p] = (p_wchar0) n;
} break; case 1: { p_wchar1 *s = STR1(output.s); INT_TYPE p = output.s->len; while (--p>i) s[p] = s[p-1];
-
s[p] =
DO_NOT_WARN
(
(
p_wchar1) n
)
;
+
s[p] = (p_wchar1) n;
} break; case 2: { p_wchar2 *s = STR2(output.s); INT_TYPE p = output.s->len; while (--p>i) s[p] = s[p-1];
-
s[p] =
DO_NOT_WARN
(
(
p_wchar2) n
)
;
+
s[p] = (p_wchar2) n;
} break;
-
#ifdef PIKE_DEBUG
-
default:
-
Pike_fatal("Illegal shift size!\n");
-
#endif
+
} i++; } RETURN finish_string_builder( &output ); } /*! @decl string encode(string s) *! *! Encodes a string using Bootstring encoding into a string constisting
pike.git/src/builtin.cmod:4272:
*! Array that @[__automap__()] is to loop over. *! *! @param depth *! Recursion depth of @[arr] where the loop will be. */ PIKEFUN void create(array a, int d) { if(THIS->arg) free_array(THIS->arg); add_ref(THIS->arg=a); THIS->depth=d;
+
pop_n_elems(2);
} PIKEFUN string _sprintf(int mode, mapping flags) { pop_n_elems(args); if (mode != 'O') { push_undefined (); return; }
-
push_text("%O%*'[*]'n");
+
push_
static_
text("%O%*'[*]'n");
if(THIS->arg) ref_push_array(THIS->arg); else push_int(0); push_int(THIS->depth*3); f_sprintf(3); } } /*! @endclass
pike.git/src/builtin.cmod:4316:
TYPE_FIELD types; for(e=0;e<args;e++) { if(TYPEOF(real_args[e]) == T_OBJECT && real_args[e].u.object->prog == automap_marker_program && OBJ2_AUTOMAP_MARKER(real_args[e].u.object)->depth >= d) { if(TYPEOF(tmpargs[e]) != T_ARRAY) index_error("__automap__",
-
Pike_sp-args,
+
args, tmpargs, NULL, "Automap on non-array.\n"); tmp=tmpargs[e].u.array->size; if(tmp < size) size=tmp; } }
pike.git/src/builtin.cmod:4449:
*! *! This is the function returned by @[_get_setter()]. */ PIKEFUN void `()(mixed val) flags ID_PROTECTED; { if (!THIS->o) { Pike_error("Uninitialized Setter!\n"); } object_low_set_index(THIS->o, THIS->f, Pike_sp-1);
-
pop_n_elems(args);
-
push_int(0);
+
}
-
+
PIKEFUN string _sprintf(int c, mapping|void opts) flags ID_PROTECTED; { struct program *prog; if (!THIS->o) {
-
push_
constant
_text("Setter()");
+
push_
static
_text("Setter()");
} else if ((prog = THIS->o->prog)) {
-
push_
constant
_text("%O->`%s=");
+
push_
static
_text("%O->`%s=");
ref_push_object(THIS->o); ref_push_string(ID_FROM_INT(prog, THIS->f)->name); f_sprintf(3); } else {
-
push_
constant
_text("Setter(destructed object)");
+
push_
static
_text("Setter(destructed object)");
} stack_pop_n_elems_keep_top(args); } } /*! @endclass */ PMOD_EXPORT struct object *get_setter(struct object *o, int f) {
pike.git/src/builtin.cmod:4560:
flags ID_PROTECTED; { RETURN 1; } PIKEFUN string _sprintf(int fmt, mixed ... extras) flags ID_PROTECTED; { pop_n_elems(args); if (fmt == 'O') {
-
push_
constant
_text("Val.null");
+
push_
static
_text("Val.null");
} else { push_undefined(); } } PIKEFUN int __hash() flags ID_PROTECTED; {
-
pop_n_elems(args);
-
push_int(
17
)
;
+
RETURN
17;
} PIKEFUN int `==(mixed other) flags ID_PROTECTED; {
-
if (TYPEOF(*other) != T_OBJECT)
{
-
pop_stack();
-
push_int(
0
)
;
-
return;
-
}
+
if (TYPEOF(*other) != T_OBJECT)
+
RETURN
0;
/* Look for the is_val_null constant directly in the program of * other, without going through its `[]. When this is called in a * codec, other can be a completely arbitrary object which may not * have a `[] that works in that context. */ push_int (0); ref_push_program (other->u.object->prog); push_constant_text("is_val_null"); if (program_index_no_free (Pike_sp - 3, Pike_sp - 2, Pike_sp - 1) && TYPEOF(Pike_sp[-3]) == T_INT && Pike_sp[-3].u.integer) {
pike.git/src/builtin.cmod:4607:
} } /*! @decl string encode_json() *! *! Defined for use with @[Standards.JSON.encode], so that it *! formats NULL as @expr{null@}. */ PIKEFUN string encode_json(...) {
+
pop_n_elems(args);
push_constant_text ("null"); } } /*! @endclass */
-
+
/*! @class DestructImmediate
+
*! An empty class that can be intherited to get the PROGRAM_DESTRUCT_IMMEDIATE
+
*! flag set.
+
*/
+
+
PIKECLASS DestructImmediate
+
program_flags PROGRAM_DESTRUCT_IMMEDIATE;
+
{
+
}
+
+
/*! @endclass
+
*/
+
PMOD_EXPORT PIKEFUN int levenshtein_distance(string a, string b) { int i, j, n, *lev_i, *lev_p; /* Simple cases: strings are equal or one of them is empty: */ if (a == b) RETURN 0; if (a->len == 0) RETURN b->len; if (b->len == 0) RETURN a->len;
pike.git/src/builtin.cmod:4670:
*! *! The base class for serializable objects. *! *! Inherit this class in classes that need to be serializable. *! *! @seealso *! @[Serializer.serialize()], @[Serializer.deserialize()] */ PIKECLASS Serializable {
-
/* Loop over all variables, and call fun_num in the current object. */
+
/* Loop over all
true
variables, and call fun_num in the current object. */
static void low_serialize(int i, struct svalue *fun, int use_setter, int fun_num) { struct inherit *inh; struct program *p = Pike_fp->current_object->prog; struct svalue *save_sp = Pike_sp; inh = p->inherits + i; p = inh->prog; for (i = 0; i < p->num_identifier_references; i++) { struct reference *ref = PTR_FROM_INT(p, i); struct identifier *id; if ((ref->id_flags & ID_HIDDEN) || ((ref->id_flags & (ID_PRIVATE|ID_INHERITED)) == (ID_PRIVATE|ID_INHERITED))) { continue; } id = ID_FROM_PTR(p, ref);
-
if (!IDENTIFIER_IS_VARIABLE(id->identifier_flags)) {
+
if (!IDENTIFIER_IS_VARIABLE(id->identifier_flags)
||
+
(id->run_time_type == PIKE_T_GET_SET
)
)
{
continue; } push_svalue(fun); if (use_setter) { push_function(get_setter(Pike_fp->current_object, i + inh->identifier_level), f_Setter_cq__backtick_28_29_fun_num); } else { low_object_index_no_free(Pike_sp, Pike_fp->current_object, i + inh->identifier_level);
pike.git/src/builtin.cmod:4752:
*! @[_serialize()], @[_deserialize_variable()] */ PIKEFUN void _serialize_variable(function(mixed, string, type:void) serializer, mixed value, string symbol, type symbol_type) flags ID_PROTECTED; rawtype tFunc(tFunc(tMix tStr tType(tMix), tVoid) tMix tStr tType(tMix), tVoid); { f_call_function(args);
-
pop_stack();
-
push_int(0);
+
} /*! @decl protected void _serialize(object o, @ *! function(mixed, string, type:void) serializer) *! *! Dispatch function for serialization. *! *! @param o *! Object to serialize. Always a context of the current object. *!
pike.git/src/builtin.cmod:4797:
*! @seealso *! @[Serializer.serialize()], @[_serialize_variable()], *! @[_deserialize()] */ PIKEFUN void _serialize(object o, function(mixed, string, type:void) serializer) flags ID_PROTECTED; rawtype tFunc(tObj tFunc(tMix tStr tType(tMix), tVoid), tVoid); { if (o != Pike_fp->current_object) {
-
SIMPLE_
BAD_
ARG_ERROR("_serialize", 1, "this");
+
SIMPLE_ARG_
TYPE_
ERROR("_serialize", 1, "this");
} low_serialize(SUBTYPEOF(Pike_sp[-args]), serializer, 0, f_Serializable_cq__serialize_variable_fun_num);
-
pop_n_elems(args);
-
push_int(0);
+
} static void *find_program_from_object_type_cb(struct pike_type *t) { struct program *p; if ((t->type != PIKE_T_OBJECT) || !t->cdr) return NULL; p = id_to_program(CDR_TO_INT(t)); if (!p || (p->flags & PROGRAM_NEEDS_PARENT) || (low_find_lfun(p, LFUN__DESERIALIZE) == -1)) return NULL; return p;
pike.git/src/builtin.cmod:4897:
struct object *o = clone_object(p, 0); push_object(o); /* Protection against errors and arg to deserialize. */ ref_push_object(o); apply_svalue(setter, 1); pop_stack(); push_svalue(deserializer); f_deserialize(2); return; } f_call_function(args);
-
pop_stack();
-
push_int(0);
+
} /*! @decl protected void _deserialize(object o, @ *! function(function(mixed:void), @ *! string, type: void) deserializer) *! *! Dispatch function for deserialization. *! *! @param o *! Object to serialize. Always a context of the current object.
pike.git/src/builtin.cmod:4944:
*! @[Serializer.deserialize()], @[_deserialize_variable()], *! @[_serialize()], @[Builtin.Setter] */ PIKEFUN void _deserialize(object o, function(function(mixed:void), string, type: void) deserializer) flags ID_PROTECTED; rawtype tFunc(tObj tFunc(tFunc(tMix, tVoid) tStr tType(tMix), tVoid), tVoid); { if (o != Pike_fp->current_object) {
-
SIMPLE_
BAD_
ARG_ERROR("_serialize", 1, "this");
+
SIMPLE_ARG_
TYPE_
ERROR("_serialize", 1, "this");
} low_serialize(SUBTYPEOF(Pike_sp[-args]), deserializer, 1, f_Serializable_cq__deserialize_variable_fun_num);
-
pop_n_elems(args);
-
push_int(0);
+
} } /*! @endclass */ /*! @decl void serialize(object o, @ *! function(mixed, string, type:void) serializer) *! *! Call @[lfun::_serialize()] in @[o]. *!
pike.git/src/builtin.cmod:5034:
node->next = node->prev = NULL; node->refs = 1; SET_SVAL(node->val, T_INT, NUMBER_UNDEFINED, integer, 0); return node; } void count_memory_in_pike_list_nodes(size_t * n, size_t * s) { ba_count_all(&pike_list_node_allocator, n, s); }
-
void free_all_pike_list_node_blocks() {
+
void free_all_pike_list_node_blocks(
void
) {
ba_destroy(&pike_list_node_allocator); } PMOD_EXPORT void free_list_node(struct pike_list_node *node) { if (!sub_ref(node)) { if (node->prev) { free_list_node(node->prev); } if (node->next) {
pike.git/src/builtin.cmod:5328:
*! *! Describe the list. *! *! @seealso *! @[sprintf()], @[lfun::_sprintf()] */ PIKEFUN string _sprintf(int c, mapping(string:mixed)|void attr) flags ID_PROTECTED; { if (!THIS->num_elems) {
-
push_
constant
_text("ADT.List(/* empty */)");
+
push_
static
_text("ADT.List(/* empty */)");
} else if (c == 'O') { struct pike_list_node *node = THIS->head; if (THIS->num_elems == 1) {
-
push_
constant
_text("ADT.List(/* 1 element */\n");
+
push_
static
_text("ADT.List(/* 1 element */\n");
} else {
-
push_
constant
_text("ADT.List(/* %d elements */\n");
+
push_
static
_text("ADT.List(/* %d elements */\n");
push_int(THIS->num_elems); f_sprintf(2); } while (node->next) { if (node->next->next) {
-
push_
constant
_text(" %O,\n");
+
push_
static
_text(" %O,\n");
} else {
-
push_
constant
_text(" %O\n");
+
push_
static
_text(" %O\n");
} push_svalue(&node->val); f_sprintf(2); node = node->next; }
-
push_
constant
_text(")");
+
push_
static
_text(")");
f_add(THIS->num_elems + 2); } else { if (THIS->num_elems == 1) {
-
push_
constant
_text("ADT.List(/* 1 element */)");
+
push_
static
_text("ADT.List(/* 1 element */)");
} else {
-
push_
constant
_text("ADT.List(/* %d elements */)");
+
push_
static
_text("ADT.List(/* %d elements */)");
push_int(THIS->num_elems); f_sprintf(2); } } stack_pop_n_elems_keep_top(args); } /*! @decl mixed head() *! *! Get the element at the head of the list.
pike.git/src/builtin.cmod:5472:
if (THIS->num_elems) { struct pike_list_node *node = THIS->head; int i; for (i = 0; i < THIS->num_elems; i++) { assign_svalue_no_free(ITEM(a) + i, &node->val); node = node->next; } } }
-
/*! @decl
mixed
cast(string type)
+
/*! @decl
array
cast(string type)
*!
-
*! Cast the lists. @expr{array@}
and
@expr{object@} are
the only
-
*! supported
types
.
+
*! Cast the lists. @expr{array@}
is
the only
+
*! supported
type
.
*/
-
PIKEFUN
mixed
cast(string type)
+
PIKEFUN
array
cast(string type)
flags ID_PROTECTED; {
-
if (
type
==
MK_STRING("array"))
{
-
pop
_
n
_
elems(args
)
;
+
pop_stack();
/*
type
as
at
least one more reference. */
+
if
(type
==
literal
_
array
_
string
)
apply_current(f_List_cq__values_fun_num, 0);
-
}
else
if (type == MK_STRING("object")) {
-
pop_n_elems(args);
-
ref_
push_
object
(
Pike_fp->current_object
);
-
} else {
-
Pike_error("Cannot cast to %o.\n", Pike_sp-1);
+
else
+
push_
undefined
();
}
-
}
+
/*! @decl mixed `[](mixed key) */ PIKEFUN mixed `[](mixed key) flags ID_PROTECTED; { struct pike_list_node *node; INT_TYPE n;
-
if (TYPEOF(*key) != PIKE_T_INT) SIMPLE_
BAD_
ARG_ERROR("`[]", 1, "int");
+
if (TYPEOF(*key) != PIKE_T_INT) SIMPLE_ARG_
TYPE_
ERROR("`[]", 1, "int");
n = key->u.integer; if (n < 0) n = -(n+1); if (n >= THIS->num_elems) Pike_error("out of bounds"); if (n >= THIS->num_elems >> 1) { /* use shorter direction */ n = THIS->num_elems - n - 1; key->u.integer = - key->u.integer - 1; }
pike.git/src/builtin.cmod:5539:
PIKEFUN void append(mixed ... values) { struct pike_list_node *node = TAIL_SENTINEL(THIS); while (args--) { struct pike_list_node *new_node = alloc_pike_list_node(); new_node->val = *(--Pike_sp); prepend_list_node(node, new_node); free_list_node(node = new_node); THIS->num_elems++; }
-
push_int(0);
+
} /*! @decl void insert(mixed ... values) *! *! Insert @[values] at the front of the list. *! *! @seealso *! @[append()] */ PIKEFUN void insert(mixed ... values) { struct pike_list_node *node = THIS->head; while (args--) { struct pike_list_node *new_node = alloc_pike_list_node(); new_node->val = *(--Pike_sp); prepend_list_node(node, new_node); free_list_node(node = new_node); THIS->num_elems++; }
-
push_int(0);
+
} /*! @decl void flush() *! *! Empties the List. */ PIKEFUN void flush() { if (THIS->num_elems) { while (THIS->head->next) { if (THIS->head->refs == 2)
pike.git/src/builtin.cmod:5751:
#endif /* PIKE_DEBUG */ /* Detached node. */ gc_recurse_svalues(&THIS->cur->val, 1); gc_recurse_list_node_tree_forward(THIS->cur->next, THIS->cur->prev); gc_recurse_list_node_tree_backward(THIS->cur->next, THIS->cur->prev); } PIKEFUN int(0..1) `!() flags ID_PROTECTED; {
-
pop_n_elems(args);
-
push_int
(!THIS->cur->next || !THIS->cur->prev);
+
RETURN
(!THIS->cur->next || !THIS->cur->prev);
} PIKEFUN int(0..) index() { pop_n_elems(args); if (THIS->cur->next && THIS->cur->prev) { push_int(THIS->ind); } else { push_undefined(); }
pike.git/src/builtin.cmod:5831:
*! @seealso *! @[prev()] */ PIKEFUN int(0..1) next() { struct pike_list_node *next; if ((next = THIS->cur->next)) { free_list_node(THIS->cur); add_ref(THIS->cur = next); THIS->ind++;
-
if (next->next)
{
-
pop_n_elems(args);
-
push_int(
1
)
;
-
return;
+
if (next->next)
+
RETURN
1;
}
-
+
RETURN 0;
}
-
pop_n_elems(args);
-
push_int(0);
-
}
+
/*! @decl int(0..1) prev() *! *! Retrace to the previous element in the list. *! *! @returns *! Returns @expr{1@} on success, and @expr{0@} (zero) *! at the beginning of the list. *! *! @seealso *! @[next()] */ PIKEFUN int(0..1) prev() { struct pike_list_node *prev; if ((prev = THIS->cur->prev)) { free_list_node(THIS->cur); add_ref(THIS->cur = prev); THIS->ind--;
-
if (prev->prev)
{
-
pop_n_elems(args);
-
push_int(
1
)
;
-
return;
+
if (prev->prev)
+
RETURN
1;
}
-
+
RETURN 0;
}
-
pop_n_elems(args);
-
push_int(0);
-
}
+
/*! @decl Iterator `+=(int steps) *! *! Advance or retrace the specified number of @[steps]. *! *! @seealso *! @[next()], @[prev] */ PIKEFUN Iterator `+=(int steps) {
pike.git/src/builtin.cmod:5913:
struct pike_list_node *new_node; if (!THIS->cur->prev) { Pike_error("Attempt to insert before the start sentinel.\n"); } new_node = alloc_pike_list_node(); assign_svalue_no_free(&new_node->val, val); prepend_list_node(THIS->cur, new_node); free_list_node(THIS->cur); THIS->cur = new_node; List__get_iterator_find_parent()->num_elems++;
-
pop_n_elems(args);
-
push_int(0);
+
} /*! @decl void append(mixed val) *! *! Append @[val] after the current position. *! *! @seealso *! @[insert()], @[delete()], @[set()] */ PIKEFUN void append(mixed val) { struct pike_list_node *new_node; if (!THIS->cur->next) { Pike_error("Attempt to append after the end sentinel.\n"); } new_node = alloc_pike_list_node(); assign_svalue_no_free(&new_node->val, val); append_list_node(THIS->cur, new_node); free_list_node(new_node); List__get_iterator_find_parent()->num_elems++;
-
pop_n_elems(args);
-
push_int(0);
+
} /*! @decl void delete() *! *! Delete the current node. *! *! The current position will advance to the next node. *! This function thus performes the reverse operation *! of @[insert()]. *!
pike.git/src/builtin.cmod:5968:
if (THIS->cur->refs == 3) { unlink_list_node(THIS->cur); } else { /* There's some other iterator holding references to this node. */ detach_list_node(THIS->cur); } List__get_iterator_find_parent()->num_elems--; } free_list_node(THIS->cur); THIS->cur = next;
-
pop_n_elems(args);
-
push_int(0);
+
} /*! @decl void set(mixed val) *! *! Set the value of the current position to @[val]. *! *! @seealso *! @[insert()], @[append()], @[delete()] */ PIKEFUN void set(mixed val) { if (!THIS->cur->next || !THIS->cur->prev) { Pike_error("Attempt to set a sentinel.\n"); } assign_svalue(&THIS->cur->val, val);
-
pop_n_elems(args);
-
push_int(0);
+
} } /*! @endclass */ } /*! @endclass */ /*! @endmodule */
-
+
/*! @module __builtin
+
*/
+
+
/*! @class Stack
+
*! This class implements a simple stack. Instead of adding and removing
+
*! elements to an array, and thus making it vary in size for every push
+
*! and pop operation, this stack tries to keep the stack size constant.
+
*! If however the stack risks to overflow, it will allocate double its
+
*! current size, i.e. pushing an element on an full 32 slot stack will
+
*! result in a 64 slot stack with 33 elements.
+
*!
+
*! @note
+
*! This class is usually accessed as @[ADT.LowLevelStack].
+
*/
+
PIKECLASS Stack
+
{
+
PIKEVAR array arr;
+
+
/*! @decl void push(mixed val)
+
*! Push an element on the top of the stack.
+
*/
+
PIKEFUN void push(mixed val)
+
{
+
if (!THIS->arr) {
+
THIS->arr = real_allocate_array(1, 31);
+
array_set_index_no_free(THIS->arr, 0, val);
+
} else {
+
THIS->arr = array_insert(THIS->arr, val, THIS->arr->size);
+
}
+
push_int(0);
+
}
+
+
/*! @decl mixed top()
+
*! Returns the top element from the stack, without
+
*! popping it.
+
*! @throws
+
*! Throws an error if called on an empty stack.
+
*/
+
PIKEFUN mixed top()
+
{
+
if (THIS->arr && THIS->arr->size) {
+
push_svalue(ITEM(THIS->arr) + THIS->arr->size - 1);
+
return;
+
}
+
Pike_error("Stack underflow\n");
+
}
+
+
/*! @decl mixed pop(void|int val)
+
*! Pops and returns entry @[val] from the stack, counting
+
*! from the top. If no value is given the top element is
+
*! popped and returned. All popped entries are freed from
+
*! the stack.
+
*/
+
PIKEFUN mixed pop(void|int val)
+
{
+
if (!THIS->arr || !THIS->arr->size) {
+
Pike_error("Stack underflow\n");
+
}
+
+
if (val && (val->u.integer > 0)) {
+
ptrdiff_t new_size;
+
ptrdiff_t old_size;
+
+
new_size = THIS->arr->size - val->u.integer;
+
if (new_size < 0) new_size = 0;
+
+
/* NB: Steal reference from the array element. */
+
*Pike_sp = ITEM(THIS->arr)[new_size];
+
old_size = THIS->arr->size;
+
THIS->arr->size = new_size;
+
Pike_sp++;
+
+
free_svalues(ITEM(THIS->arr) + new_size + 1, old_size - (new_size + 1),
+
THIS->arr->type_field);
+
} else {
+
/* NB: Steal reference from the array element. */
+
THIS->arr->size--;
+
*Pike_sp = ITEM(THIS->arr)[THIS->arr->size];
+
Pike_sp++;
+
}
+
}
+
+
/*! @decl void quick_pop(void|int val)
+
*! Pops @[val] entries from the stack, or one entry
+
*! if no value is given. The popped entries are not
+
*! returned.
+
*/
+
PIKEFUN void quick_pop(void|int val)
+
{
+
apply_current(f_Stack_pop_fun_num, args);
+
push_int(0);
+
}
+
+
/*! @decl void reset(int|void initial_size)
+
*! Empties the stack, resets the stack pointer
+
*! and shrinks the stack size to the given value
+
*! or 32 if none is given.
+
*! @seealso
+
*! @[create]
+
*/
+
PIKEFUN void reset(int|void initial_size)
+
{
+
ptrdiff_t size = 32;
+
if (initial_size && (initial_size->u.integer > 0)) {
+
size = initial_size->u.integer;
+
}
+
+
if (THIS->arr) {
+
free_array(THIS->arr);
+
THIS->arr = NULL;
+
}
+
+
/* NB: The initial size MUST != 0 else the empty array will be returned. */
+
THIS->arr = real_allocate_array(1, size-1);
+
THIS->arr->size = 0;
+
}
+
+
/*! @decl void create(int|void initial_size)
+
*! An initial stack size can be given when
+
*! a stack is cloned. The default value is
+
*! 32.
+
*/
+
PIKEFUN void create(int|void initial_size)
+
{
+
apply_current(f_Stack_reset_fun_num, args);
+
}
+
+
/*! @decl void set_stack(array stack)
+
*! Sets the stacks content to the provided array.
+
*/
+
PIKEFUN void set_stack(array stack)
+
{
+
if (THIS->arr) {
+
free_array(THIS->arr);
+
}
+
add_ref(THIS->arr = stack);
+
}
+
+
/*! @decl int _sizeof()
+
*! @[sizeof] on a stack returns the number of entries
+
*! in the stack.
+
*/
+
PIKEFUN int _sizeof()
+
flags ID_PROTECTED;
+
{
+
push_int(THIS->arr ? THIS->arr->size : 0);
+
}
+
+
/*! @decl array _values()
+
*! @[values] on a stack returns all the entries in
+
*! the stack, in order.
+
*/
+
PIKEFUN array _values()
+
flags ID_PROTECTED;
+
{
+
if (THIS->arr) {
+
push_array(copy_array(THIS->arr));
+
} else {
+
ref_push_array(&empty_array);
+
}
+
}
+
+
/*! @decl int _search(mixed item)
+
*! Return the stack-depth to @[item].
+
*!
+
*! This function makes it possible to use
+
*! eg @[search()] and @[has_value()] on the stack.
+
*/
+
PIKEFUN int _search(mixed item)
+
flags ID_PROTECTED;
+
{
+
if (!THIS->arr || !THIS->arr->size) {
+
push_int(-1);
+
} else {
+
push_int(array_search(THIS->arr, item, 0));
+
}
+
}
+
+
/*! @decl this_program `+(this_program s)
+
*! A stack added with another stack yields a new
+
*! stack with all the elements from both stacks,
+
*! and the elements from the second stack at the
+
*! top of the new stack.
+
*/
+
PIKEFUN Stack `+(Stack s)
+
flags ID_PROTECTED;
+
{
+
struct Stack_struct *other_st = get_storage(s, Stack_program);
+
int cnt = 0;
+
if (!other_st) {
+
SIMPLE_BAD_ARG_ERROR("`+", 1, "Stack");
+
}
+
if (THIS->arr) {
+
ref_push_array(THIS->arr);
+
cnt++;
+
}
+
if (other_st->arr) {
+
ref_push_array(other_st->arr);
+
cnt++;
+
}
+
if (cnt == 1) {
+
ref_push_array(&empty_array);
+
}
+
if (cnt) {
+
f_add(2);
+
#ifdef PIKE_DEBUG
+
if (TYPEOF(Pike_sp[-1]) != PIKE_T_ARRAY) {
+
Pike_fatal("Stack addition failure.\n");
+
}
+
#endif
+
push_object(s = fast_clone_object(Stack_program));
+
other_st = get_storage(s, Stack_program);
+
#ifdef PIKE_DEBUG
+
if (!other_st) {
+
Pike_fatal("Stack lost storage.\n");
+
}
+
#endif
+
add_ref(other_st->arr = Pike_sp[-2].u.array);
+
return;
+
}
+
push_object(clone_object(Stack_program, 0));
+
}
+
+
PIKEFUN mixed cast(string to)
+
flags ID_PROTECTED;
+
{
+
if( to == MK_STRING("array") ) {
+
apply_current(f_Stack_cq__values_fun_num, 0);
+
} else {
+
push_undefined();
+
}
+
}
+
+
PIKEFUN string _sprintf(int t)
+
flags ID_PROTECTED;
+
{
+
if (t != '0') {
+
push_undefined();
+
}
+
+
push_constant_text("%O%O");
+
ref_push_program(Pike_fp->current_program);
+
apply_current(f_Stack_cq__values_fun_num, 0);
+
f_sprintf(3);
+
}
+
}
+
/*! @endclass
+
*/
+
+
/*! @endmodule
+
*/
+
/*! @module Pike */ /*! @class MasterCodec *! *! This is a bare-bones codec that is used when loading a dumped master. *! *! @seealso *! @[Codec] */
pike.git/src/builtin.cmod:6056:
} /*! @endclass */ /*! @endmodule */ static struct object *val_module;
-
static void get_val_module()
+
static void get_val_module(
void
)
{ assert (!val_module);
-
push_
constant
_text ("Val");
+
push_
static
_text ("Val");
APPLY_MASTER ("resolv", 1); if (TYPEOF(Pike_sp[-1]) != T_OBJECT) Pike_error ("\"Val\" didn't resolve to a module object.\n"); val_module = (--Pike_sp)->u.object; } /* Always do the lookup in the Val module dynamically to allow the * values to be replaced. */ #define GET_VAL(NAME) \ PMOD_EXPORT struct object *PIKE_CONCAT (get_val_, NAME) (void) \
pike.git/src/builtin.cmod:6099:
return Null_program; } PIKECLASS __Backtrace_Tester__ { INIT { Pike_error("__Backtrace_Tester__\n"); } }
+
#undef DEFAULT_CMOD_STORAGE
+
#define DEFAULT_CMOD_STORAGE static
+
+
PIKECLASS pike_trampoline
+
{
+
CVAR struct pike_trampoline trampoline;
+
+
DECLARE_STORAGE;
+
+
#ifdef PIKE_NULL_IS_SPECIAL
+
INIT
+
{
+
THIS->trampoline.frame=0;
+
}
+
#endif
+
+
EXIT
+
{
+
if(THIS->trampoline.frame)
+
{
+
free_pike_scope(THIS->trampoline.frame);
+
THIS->trampoline.frame=0;
+
}
+
}
+
+
static void gc_check_frame(struct pike_frame *f)
+
{
+
if(f->flags & PIKE_FRAME_MALLOCED_LOCALS)
+
{
+
if(f->current_object)
+
debug_gc_check (f->current_object, " as current_object in trampoline frame");
+
if(f->current_program)
+
debug_gc_check (f->current_program, " as current_program in trampoline frame");
+
debug_gc_check_svalues (f->locals, f->num_locals, " in locals of trampoline frame");
+
if(f->scope && !debug_gc_check (f->scope, " as scope frame of trampoline frame"))
+
gc_check_frame(f->scope);
+
}
+
}
+
+
GC_CHECK
+
{
+
if (THIS->trampoline.frame &&
+
!debug_gc_check(THIS->trampoline.frame, " as trampoline frame"))
+
gc_check_frame(THIS->trampoline.frame);
+
}
+
+
static void gc_recurse_frame(struct pike_frame *f)
+
{
+
if(f->current_object) gc_recurse_object(f->current_object);
+
if(f->current_program) gc_recurse_program(f->current_program);
+
if(f->flags & PIKE_FRAME_MALLOCED_LOCALS)
+
gc_recurse_svalues(f->locals,f->num_locals);
+
if(f->scope) gc_recurse_frame(f->scope);
+
}
+
+
GC_RECURSE
+
{
+
if (THIS->trampoline.frame) gc_recurse_frame(THIS->trampoline.frame);
+
}
+
+
PIKEFUN void `()(mixed ... ignored)
+
{
+
Pike_error("Internal error: Trampoline magic failed!\n");
+
}
+
+
PIKEFUN int(0..1) `!()
+
{
+
if (!THIS->trampoline.frame || !THIS->trampoline.frame->current_object ||
+
!THIS->trampoline.frame->current_object->prog) {
+
push_int(1);
+
} else {
+
push_int(0);
+
}
+
}
+
+
PIKEFUN string _sprintf(int c, mapping|void opts)
+
{
+
struct byte_buffer buf = BUFFER_INIT();
+
+
if (!args || TYPEOF(Pike_sp[-args]) != T_INT ||
+
Pike_sp[-args].u.integer != 'O' ||
+
!THIS->trampoline.frame || !THIS->trampoline.frame->current_object) {
+
pop_n_elems (args);
+
push_int (0);
+
return;
+
}
+
pop_n_elems (args);
+
+
ref_push_function (THIS->trampoline.frame->current_object,
+
THIS->trampoline.func);
+
describe_svalue (&buf, Pike_sp - 1, 0, 0);
+
pop_stack();
+
push_string(buffer_finish_pike_string(&buf));
+
}
+
}
+
void init_builtin(void) { SET_SVAL(gc_pre_cb, PIKE_T_INT, NUMBER_NUMBER, integer, 0); SET_SVAL(gc_post_cb, PIKE_T_INT, NUMBER_NUMBER, integer, 0); SET_SVAL(gc_destruct_cb, PIKE_T_INT, NUMBER_NUMBER, integer, 0); SET_SVAL(gc_done_cb, PIKE_T_INT, NUMBER_NUMBER, integer, 0);
-
INIT
+
INIT
;
} void exit_builtin(void) { struct svalue zero; if (val_module) free_object (val_module);
-
EXIT
+
EXIT
;
SET_SVAL(zero, PIKE_T_INT, NUMBER_NUMBER, integer, 0); assign_svalue(&gc_pre_cb, &zero); assign_svalue(&gc_post_cb, &zero); assign_svalue(&gc_destruct_cb, &zero); assign_svalue(&gc_done_cb, &zero); #ifndef DO_PIKE_CLEANUP /* This is performed by exit_builtin_modules() at a later point * in this case, so that the pike_list_node's are valid at cleanup * time, thus avoiding "got invalid pointer" fatals at exit. */ ba_destroy(&pike_list_node_allocator); #endif #ifndef USE_SETENV if (env_allocs) free_mapping (env_allocs); #endif
-
+
#ifdef __NT__
+
if (crypto_handle) CloseHandle(crypto_handle);
+
#else
+
if (random_fd!=-1) close(random_fd);
+
#endif
}