/* -*- c -*- |
* $Id: builtin.cmod,v 1.19 2001/06/15 00:26:09 mast Exp $ |
*/ |
|
#include "global.h" |
#include "interpret.h" |
#include "svalue.h" |
#include "opcodes.h" |
#include "pike_macros.h" |
#include "object.h" |
#include "program.h" |
#include "array.h" |
#include "pike_error.h" |
#include "constants.h" |
#include "mapping.h" |
#include "stralloc.h" |
#include "multiset.h" |
#include "pike_types.h" |
#include "pike_memory.h" |
#include "threads.h" |
#include <math.h> |
#include <ctype.h> |
#include "module_support.h" |
#include "cyclic.h" |
#include "bignum.h" |
#include "main.h" |
#include "operators.h" |
#include "builtin_functions.h" |
|
//! 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])@} |
//! |
//! Except of course it is a lot shorter and faster. |
//! That is, it indices every index in the array data on the value of |
//! the argument index and returns an array with the results. |
//! |
//! @seealso |
//! @[rows()] |
//! |
PIKEFUN array column(array data, mixed index) |
efun; |
optflags OPT_TRY_OPTIMIZE; |
{ |
INT32 e; |
struct array *a; |
|
DECLARE_CYCLIC(); |
|
/* Optimization */ |
if(data->refs == 1) |
{ |
/* An array with one ref cannot possibly be cyclic */ |
struct svalue sval; |
data->type_field = BIT_MIXED | BIT_UNFINISHED; |
for(e=0;e<data->size;e++) |
{ |
index_no_free(&sval, ITEM(data)+e, index); |
free_svalue(ITEM(data)+e); |
ITEM(data)[e]=sval; |
} |
pop_stack(); |
return; |
} |
|
if((a=(struct array *)BEGIN_CYCLIC(data,0))) |
{ |
add_ref(a); |
}else{ |
push_array(a=allocate_array(data->size)); |
SET_CYCLIC_RET(a); |
|
for(e=0;e<a->size;e++) |
index_no_free(ITEM(a)+e, ITEM(data)+e, index); |
|
sp--; |
} |
END_CYCLIC(); |
RETURN a; |
} |
|
//! This function creates a multiset from an array. |
//! |
//! @seealso |
//! @[aggregate_multiset()] |
//! |
PIKEFUN multiset(1) mkmultiset(array(1=mixed) a) |
efun; |
optflags OPT_TRY_OPTIMIZE|OPT_EXTERNAL_DEPEND; |
{ |
RETURN mkmultiset(a); |
} |
|
//! This function changes the debug trace level. |
//! |
//! The old level is returned. |
//! |
//! Trace level 1 or higher means that calls to Pike functions are |
//! printed to stderr, level 2 or higher means calls to builtin functions |
//! are printed, 3 means every opcode interpreted is printed, 4 means |
//! arguments to these opcodes are printed as well. |
//! |
//! See the @tt{-t@} command-line option for more information. |
//! |
PIKEFUN int trace(int t) |
efun; |
optflags OPT_SIDE_EFFECT; |
{ |
pop_n_elems(args); |
push_int(t_flag); |
t_flag=t; |
} |
|
//! Convert the output from a previous call to @[time()] into a readable |
//! string containing the current year, month, day and time. |
//! |
//! @seealso |
//! @[time()], @[localtime()], @[mktime()], @[gmtime()] |
//! |
PIKEFUN string ctime(int timestamp) |
efun; |
optflags OPT_TRY_OPTIMIZE; |
{ |
time_t i=(time_t)timestamp; |
RETURN make_shared_string(ctime(&i)); |
} |
|
//! Make a mapping from two arrays. |
//! |
//! Makes a mapping @[ind[x]]:@[val[x]], @tt{0 <= x < sizeof(ind)@}. |
//! |
//! @[ind] and @[val] must have the same size. |
//! |
//! This is the inverse operation of @[indices()] and @[values()]. |
//! |
//! @seealso |
//! @[indices()], @[values()] |
//! |
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", sp-args, args, 2, "array", sp+1-args, |
"mkmapping called on arrays of different sizes (%d != %d)\n", |
ind->size, val->size); |
|
RETURN mkmapping(ind, val); |
} |
|
//! Count the number of non-overlapping times the string @[needle] occurrs |
//! in the string @[haystack]. |
//! |
//! @seealso |
//! @[search()], @[`/()] |
//! |
PIKEFUN int string_count(string haystack, string needle) |
errname String.count; |
optflags OPT_TRY_OPTIMIZE; |
{ |
ptrdiff_t c = 0; |
ptrdiff_t i, j; |
|
switch (needle->len) |
{ |
case 0: |
switch (haystack->len) |
{ |
case 0: c=1; break; /* "" appears one time in "" */ |
case 1: c=0; break; /* "" doesn't appear in "x" */ |
default: c=haystack->len-1; /* one time between each character */ |
} |
break; |
case 1: |
/* maybe optimize? */ |
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); |
} |
|
//! Returns 1 if @[prog] implements @[api]. |
//! |
PIKEFUN int program_implements(program prog, program api) |
errname Program.implements; |
optflags OPT_TRY_OPTIMIZE; |
{ |
RETURN implements(prog, api); |
} |
|
//! Returns 1 if @[child] has inherited @[parent]. |
//! |
PIKEFUN int program_inherits(program child, program parent) |
errname Program.inherits; |
optflags OPT_TRY_OPTIMIZE; |
{ |
RETURN !!low_get_storage(parent, child); |
} |
|
//! Returns a string with filename and linenumber describing where |
//! the program @[p] was defined. |
//! |
//! The returned string is of the format @tt{"@i{filename@}:@i{linenumber@}"@}. |
//! |
//! If it cannot be determined where the program was defined, @tt{0@} (zero) |
//! will be returned. |
//! |
PIKEFUN string program_defined(program p) |
errname Program.defined; |
optflags OPT_TRY_OPTIMIZE; |
{ |
if(p && p->num_linenumbers) |
{ |
char *tmp; |
INT32 line; |
if((tmp=get_line(p->program, p, &line))) |
{ |
struct pike_string *tmp2; |
tmp2=make_shared_string(tmp); |
pop_n_elems(args); |
|
push_string(tmp2); |
if(line > 1) |
{ |
push_constant_text(":"); |
push_int(line); |
f_add(3); |
} |
return; |
} |
} |
|
pop_n_elems(args); |
push_int(0); |
} |
|
//! Returns the width of a string. |
//! |
//! Three return values are possible: |
//! @int |
//! @value 8 |
//! The string @[s] only contains characters <= 255. |
//! @value 16 |
//! The string @[s] only contains characters <= 65535. |
//! @value 32 |
//! The string @[s] contains characters >= 65536. |
//! @endint |
//! |
PIKEFUN int string_width(string s) |
errname String.width; |
optflags OPT_TRY_OPTIMIZE; |
{ |
RETURN 8 * (1 << s->size_shift); |
} |
|
//! Removes the entry with index @[index] from mapping @[map] destructively. |
//! |
//! If the mapping does not have an entry with index @[index], nothing is done. |
//! |
//! @returns |
//! The value that was removed will be returned. |
//! |
//! @note |
//! Note that @[m_delete()] changes @[map] destructively. |
//! |
//! @seealso |
//! @[mappingp()] |
//! |
PIKEFUN mixed m_delete(object|mapping map, mixed index) |
efun; |
optflags OPT_SIDE_EFFECT; |
{ |
/*FIXME: Should be |
* type function(mapping(1=mixed:2=mixed),1:2)| |
* function(object,mixed:mixed); |
* |
* or similar |
*/ |
if( map->type == T_MAPPING ) |
{ |
struct svalue s; |
map_delete_no_free(map->u.mapping, index, &s); |
pop_n_elems(args); |
*sp=s; |
sp++; |
} |
else if (map->type == T_OBJECT) |
{ |
int id = FIND_LFUN(map->u.object->prog, LFUN__M_DELETE); |
|
if( id == -1 ) |
SIMPLE_BAD_ARG_ERROR("m_delete", 1, "object with _m_delete"); |
|
apply_low( map->u.object, id, 1 ); |
stack_swap(); |
pop_stack(); |
} else { |
SIMPLE_BAD_ARG_ERROR("m_delete", 1, "object|mapping"); |
} |
} |
|
//! Returns the weak flag settings for @[m]. It's a combination of |
//! @[Pike.WEAK_INDICES] and @[Pike.WEAK_VALUES]. |
//! |
PIKEFUN int get_weak_flag(array|mapping|multiset m) |
efun; |
optflags OPT_EXTERNAL_DEPEND; |
{ |
int flag = 0; |
switch (m->type) { |
case T_ARRAY: |
flag = (m->u.array->flags & ARRAY_WEAK_FLAG) ? PIKE_WEAK_VALUES : 0; |
break; |
case T_MAPPING: |
flag = mapping_get_flags(m->u.mapping) & MAPPING_WEAK; |
break; |
case T_MULTISET: |
flag = (m->u.multiset->ind->flags & (ARRAY_WEAK_FLAG|ARRAY_WEAK_SHRINK)) ? |
PIKE_WEAK_INDICES : 0; |
break; |
default: |
SIMPLE_BAD_ARG_ERROR("get_weak_flag",1,"array|mapping|multiset"); |
} |
pop_n_elems(args); |
push_int(flag); |
} |
|
void init_builtin(void) |
{ |
INIT |
} |
|