9da7f42001-06-05Martin Stjernholm /* -*- c -*-
f01b122001-07-01Henrik Grubbström (Grubba)  * $Id: builtin.cmod,v 1.52 2001/07/01 15:39:16 grubba Exp $
9da7f42001-06-05Martin Stjernholm  */
c3da7f2000-07-04Martin Stjernholm 
3a5b1d2000-05-24Fredrik Hübinette (Hubbe) #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"
bb8a782000-12-01Fredrik Hübinette (Hubbe) #include "pike_error.h"
3a5b1d2000-05-24Fredrik Hübinette (Hubbe) #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"
098c802000-05-24Fredrik Hübinette (Hubbe) #include "main.h"
b8c5b22000-05-25Fredrik Hübinette (Hubbe) #include "operators.h"
9da7f42001-06-05Martin Stjernholm #include "builtin_functions.h"
fed7de2001-06-28Henrik Grubbström (Grubba) #include "fsort.h"
3a5b1d2000-05-24Fredrik Hübinette (Hubbe) 
0498332001-02-10Henrik Grubbström (Grubba) /*! @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])@} *! *! 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()] */
b0f8352001-01-07Henrik Grubbström (Grubba) PIKEFUN array column(array data, mixed index)
3a5b1d2000-05-24Fredrik Hübinette (Hubbe)  efun; optflags OPT_TRY_OPTIMIZE; { INT32 e; struct array *a; DECLARE_CYCLIC(); /* Optimization */
b0f8352001-01-07Henrik Grubbström (Grubba)  if(data->refs == 1)
3a5b1d2000-05-24Fredrik Hübinette (Hubbe)  { /* An array with one ref cannot possibly be cyclic */ struct svalue sval;
b0f8352001-01-07Henrik Grubbström (Grubba)  data->type_field = BIT_MIXED | BIT_UNFINISHED; for(e=0;e<data->size;e++)
3a5b1d2000-05-24Fredrik Hübinette (Hubbe)  {
b0f8352001-01-07Henrik Grubbström (Grubba)  index_no_free(&sval, ITEM(data)+e, index); free_svalue(ITEM(data)+e); ITEM(data)[e]=sval;
3a5b1d2000-05-24Fredrik Hübinette (Hubbe)  } pop_stack(); return; }
b0f8352001-01-07Henrik Grubbström (Grubba)  if((a=(struct array *)BEGIN_CYCLIC(data,0)))
3a5b1d2000-05-24Fredrik Hübinette (Hubbe)  { add_ref(a); }else{
b0f8352001-01-07Henrik Grubbström (Grubba)  push_array(a=allocate_array(data->size));
3a5b1d2000-05-24Fredrik Hübinette (Hubbe)  SET_CYCLIC_RET(a); for(e=0;e<a->size;e++)
b0f8352001-01-07Henrik Grubbström (Grubba)  index_no_free(ITEM(a)+e, ITEM(data)+e, index);
3a5b1d2000-05-24Fredrik Hübinette (Hubbe)  sp--; } END_CYCLIC(); RETURN a; }
0498332001-02-10Henrik Grubbström (Grubba) /*! @decl multiset mkmultiset(array a) *! *! This function creates a multiset from an array. *! *! @seealso *! @[aggregate_multiset()] *! */
3a5b1d2000-05-24Fredrik Hübinette (Hubbe) PIKEFUN multiset(1) mkmultiset(array(1=mixed) a) efun;
8f998d2000-08-31Henrik Grubbström (Grubba)  optflags OPT_TRY_OPTIMIZE|OPT_EXTERNAL_DEPEND;
3a5b1d2000-05-24Fredrik Hübinette (Hubbe) { RETURN mkmultiset(a); }
0498332001-02-10Henrik Grubbström (Grubba) /*! @decl int trace(int t) *! *! 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. */
098c802000-05-24Fredrik Hübinette (Hubbe) PIKEFUN int trace(int t) efun; optflags OPT_SIDE_EFFECT; { pop_n_elems(args); push_int(t_flag); t_flag=t; }
d6fd962001-02-10Henrik Grubbström (Grubba) /*! @decl string ctime(int timestamp) *!
0498332001-02-10Henrik Grubbström (Grubba)  *! 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()] */
b0f8352001-01-07Henrik Grubbström (Grubba) PIKEFUN string ctime(int timestamp)
098c802000-05-24Fredrik Hübinette (Hubbe)  efun; optflags OPT_TRY_OPTIMIZE; {
b0f8352001-01-07Henrik Grubbström (Grubba)  time_t i=(time_t)timestamp;
098c802000-05-24Fredrik Hübinette (Hubbe)  RETURN make_shared_string(ctime(&i)); }
0498332001-02-10Henrik Grubbström (Grubba) /*! @decl mapping mkmapping(array ind, array val) *! *! 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()] */
b0f8352001-01-07Henrik Grubbström (Grubba) PIKEFUN mapping(1:2) mkmapping(array(1=mixed) ind, array(2=mixed) val)
098c802000-05-24Fredrik Hübinette (Hubbe)  efun;
8f998d2000-08-31Henrik Grubbström (Grubba)  optflags OPT_TRY_OPTIMIZE|OPT_EXTERNAL_DEPEND;
098c802000-05-24Fredrik Hübinette (Hubbe) {
b0f8352001-01-07Henrik Grubbström (Grubba)  if(ind->size != val->size)
098c802000-05-24Fredrik Hübinette (Hubbe)  bad_arg_error("mkmapping", sp-args, args, 2, "array", sp+1-args, "mkmapping called on arrays of different sizes (%d != %d)\n",
b0f8352001-01-07Henrik Grubbström (Grubba)  ind->size, val->size);
098c802000-05-24Fredrik Hübinette (Hubbe) 
b0f8352001-01-07Henrik Grubbström (Grubba)  RETURN mkmapping(ind, val);
098c802000-05-24Fredrik Hübinette (Hubbe) }
3a5b1d2000-05-24Fredrik Hübinette (Hubbe) 
269ef02001-04-18Martin Stjernholm /*! @decl int String.count(string haystack, string needle)
0498332001-02-10Henrik Grubbström (Grubba)  *! *! Count the number of non-overlapping times the string @[needle] occurrs *! in the string @[haystack]. *! *! @seealso *! @[search()], @[`/()] */
6613052000-08-10Henrik Grubbström (Grubba) PIKEFUN int string_count(string haystack, string needle)
991fdf2000-05-25Fredrik Hübinette (Hubbe)  errname String.count; optflags OPT_TRY_OPTIMIZE; {
89fc4c2000-08-10Henrik Grubbström (Grubba)  ptrdiff_t c = 0; ptrdiff_t i, j;
991fdf2000-05-25Fredrik Hübinette (Hubbe)  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; }
6613052000-08-10Henrik Grubbström (Grubba)  RETURN DO_NOT_WARN((INT_TYPE)c);
991fdf2000-05-25Fredrik Hübinette (Hubbe) }
269ef02001-04-18Martin Stjernholm /*! @decl string String.trim_whites (string s)
5117f12001-04-16Martin Stjernholm  *! *! Trim leading and trailing spaces and tabs from the string @[s]. */ PIKEFUN string string_trim_whites (string s) errname String.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; \ } \ while (--end > start) { \ chr = ((TYPE *) s->str)[end]; \ if (chr != ' ' && chr != '\t') break; \ } \ } case 0: DO_IT (p_wchar0); break; case 1: DO_IT (p_wchar1); break; case 2: DO_IT (p_wchar2); break; #undef DO_IT } RETURN string_slice (s, start, end + 1 - start); }
269ef02001-04-18Martin Stjernholm /*! @decl string String.trim_all_whites (string s)
5117f12001-04-16Martin Stjernholm  *! *! Trim leading and trailing white spaces characters (space, tab, *! newline and carriage return) from the string @[s]. */ PIKEFUN string string_trim_all_whites (string s) errname String.trim_all_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' && chr != '\n' && chr != '\r') \ break; \ } \ while (--end > start) { \ chr = ((TYPE *) s->str)[end]; \ if (chr != ' ' && chr != '\t' && chr != '\n' && chr != '\r') \ break; \ } \ } case 0: DO_IT (p_wchar0); break; case 1: DO_IT (p_wchar1); break; case 2: DO_IT (p_wchar2); break; #undef DO_IT } RETURN string_slice (s, start, end + 1 - start); }
4f985f2001-06-30Martin Stjernholm /*! @decl int Program.implements(program prog, program api)
0498332001-02-10Henrik Grubbström (Grubba)  *! *! Returns 1 if @[prog] implements @[api]. */
b0f8352001-01-07Henrik Grubbström (Grubba) PIKEFUN int program_implements(program prog, program api)
991fdf2000-05-25Fredrik Hübinette (Hubbe)  errname Program.implements; optflags OPT_TRY_OPTIMIZE; {
b0f8352001-01-07Henrik Grubbström (Grubba)  RETURN implements(prog, api);
991fdf2000-05-25Fredrik Hübinette (Hubbe) }
4f985f2001-06-30Martin Stjernholm /*! @decl int Program.inherits(program child, program parent)
0498332001-02-10Henrik Grubbström (Grubba)  *! *! Returns 1 if @[child] has inherited @[parent]. */
f3c7152001-04-14Fredrik Hübinette (Hubbe) PIKEFUN int program_inherits(program parent, program child)
991fdf2000-05-25Fredrik Hübinette (Hubbe)  errname Program.inherits; optflags OPT_TRY_OPTIMIZE; {
f3c7152001-04-14Fredrik Hübinette (Hubbe)  RETURN low_get_storage(parent, child) != -1;
991fdf2000-05-25Fredrik Hübinette (Hubbe) }
4f985f2001-06-30Martin Stjernholm /*! @decl string Program.defined(program p)
0498332001-02-10Henrik Grubbström (Grubba)  *! *! 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. */
b8c5b22000-05-25Fredrik Hübinette (Hubbe) PIKEFUN string program_defined(program p) errname Program.defined; optflags OPT_TRY_OPTIMIZE; { if(p && p->num_linenumbers) { char *tmp; INT32 line;
4f985f2001-06-30Martin Stjernholm  if((tmp=get_program_line(p, &line)))
b8c5b22000-05-25Fredrik Hübinette (Hubbe)  { struct pike_string *tmp2; tmp2=make_shared_string(tmp); pop_n_elems(args); push_string(tmp2);
4f985f2001-06-30Martin Stjernholm  if(line >= 1)
b8c5b22000-05-25Fredrik Hübinette (Hubbe)  { push_constant_text(":"); push_int(line); f_add(3); } return; } } pop_n_elems(args); push_int(0); }
269ef02001-04-18Martin Stjernholm /*! @decl int(8..8)|int(16..16)|int(32..32) String.width(string s)
0498332001-02-10Henrik Grubbström (Grubba)  *! *! 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 */
d6fd962001-02-10Henrik Grubbström (Grubba) PIKEFUN int(8 .. 8)|int(16 .. 16)|int(32 .. 32) string_width(string s)
991fdf2000-05-25Fredrik Hübinette (Hubbe)  errname String.width; optflags OPT_TRY_OPTIMIZE; { RETURN 8 * (1 << s->size_shift); }
0498332001-02-10Henrik Grubbström (Grubba) /*! @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 the signle argument. *! *! Other wise if @[map] is a mapping the entry with index @[index] *! will be removed from @[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()] */
a3453e2001-02-05Per Hedbor PIKEFUN mixed m_delete(object|mapping map, mixed index)
7f80d42000-06-19Fredrik Hübinette (Hubbe)  efun; optflags OPT_SIDE_EFFECT; {
a3453e2001-02-05Per Hedbor  /*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++; }
e9af832001-02-10Martin Stjernholm  else if (map->type == T_OBJECT && map->u.object->prog)
a3453e2001-02-05Per Hedbor  {
0498332001-02-10Henrik Grubbström (Grubba)  int id = FIND_LFUN(map->u.object->prog, LFUN__M_DELETE);
ea56012001-02-09Per Hedbor  if( id == -1 ) SIMPLE_BAD_ARG_ERROR("m_delete", 1, "object with _m_delete"); apply_low( map->u.object, id, 1 );
a3453e2001-02-05Per Hedbor  stack_swap(); pop_stack();
79f6982001-02-05Henrik Grubbström (Grubba)  } else { SIMPLE_BAD_ARG_ERROR("m_delete", 1, "object|mapping");
a3453e2001-02-05Per Hedbor  }
7f80d42000-06-19Fredrik Hübinette (Hubbe) }
9da7f42001-06-05Martin Stjernholm /*! @decl int get_weak_flag(array|mapping|multiset m)
0498332001-02-10Henrik Grubbström (Grubba)  *!
9da7f42001-06-05Martin Stjernholm  *! Returns the weak flag settings for @[m]. It's a combination of *! @[Pike.WEAK_INDICES] and @[Pike.WEAK_VALUES].
0498332001-02-10Henrik Grubbström (Grubba)  */
e1b4192001-06-06Fredrik Hübinette (Hubbe) PIKEFUN int get_weak_flag(array m)
ee9fa92000-07-06Martin Stjernholm  efun;
8f998d2000-08-31Henrik Grubbström (Grubba)  optflags OPT_EXTERNAL_DEPEND;
ee9fa92000-07-06Martin Stjernholm {
e1b4192001-06-06Fredrik Hübinette (Hubbe)  RETURN (m->flags & ARRAY_WEAK_FLAG) ? PIKE_WEAK_VALUES : 0; } PIKEFUN int get_weak_flag(mapping m) { RETURN mapping_get_flags(m) & MAPPING_WEAK; } PIKEFUN int get_weak_flag(multiset m) { RETURN (m->ind->flags & (ARRAY_WEAK_FLAG|ARRAY_WEAK_SHRINK)) ?
9da7f42001-06-05Martin Stjernholm  PIKE_WEAK_INDICES : 0;
ee9fa92000-07-06Martin Stjernholm }
aa68b12001-03-19Fredrik Hübinette (Hubbe) PIKEFUN program __empty_program() efun; optflags OPT_EXTERNAL_DEPEND; { RETURN low_allocate_program(); }
1c1c5e2001-04-08Fredrik Hübinette (Hubbe) /*! @decl string function_name(function f) *! *! Return the name of the function @[f]. *! *! If @[f] is a global function defined in the runtime @tt{0@} (zero) *! will be returned. *! *! @seealso *! @[function_object()] */ PIKEFUN string function_name(program|function func) efun; optflags OPT_TRY_OPTIMIZE; { struct pike_string *s; switch(func->type) { default: if(!func->u.object->prog) bad_arg_error("function_name", Pike_sp-args, args, 1, "function|program", Pike_sp-args, "Bad argument.\n"); return; /* NOTREACHED */ case PIKE_T_PROGRAM: { struct program *p=func->u.program; if(p->parent) { int e; p=p->parent; /* search constants in parent for this * program... */ for(e = p->num_identifier_references; e--; ) { struct identifier *id; if (p->identifier_references[e].id_flags & ID_HIDDEN) continue; id = ID_FROM_INT(p, e); if (IDENTIFIER_IS_CONSTANT(id->identifier_flags) && is_eq( & PROG_FROM_INT(p, e)->constants[id->func.offset].sval, func)) REF_RETURN id->name; } } break; } case PIKE_T_FUNCTION: if(func->subtype == FUNCTION_BUILTIN) break; if(!func->u.object->prog) bad_arg_error("function_name", Pike_sp-args, args, 1, "function", Pike_sp-args, "Destructed object.\n");
5a6d7d2001-04-10Fredrik Hübinette (Hubbe)  if(func->u.object->prog == pike_trampoline_program) { struct pike_trampoline *t; t=((struct pike_trampoline *)func->u.object->storage); if(t->frame->current_object->prog) REF_RETURN ID_FROM_INT(t->frame->current_object->prog, t->func)->name; }
1c1c5e2001-04-08Fredrik Hübinette (Hubbe)  REF_RETURN ID_FROM_INT(func->u.object->prog, func->subtype)->name; } pop_n_elems(args); push_int(0); } /*! @decl object function_object(function|program f) *! *! Return the object the function @[f] is in. *! *! If @[f] is a global function defined in the runtime @tt{0@} (zero) *! will be returned. *! *! @seealso *! @[function_name()] */
5a6d7d2001-04-10Fredrik Hübinette (Hubbe) PIKEFUN object|program function_object(object|program|function func)
1c1c5e2001-04-08Fredrik Hübinette (Hubbe)  efun; optflags OPT_TRY_OPTIMIZE;
5a6d7d2001-04-10Fredrik Hübinette (Hubbe)  type function(function|object:object)|function(program:program);
1c1c5e2001-04-08Fredrik Hübinette (Hubbe) { switch(func->type) { case PIKE_T_PROGRAM: { struct program *p; if(!(p=func->u.program->parent)) break; add_ref(p); free_program(func->u.program); func->u.program=p; return; } case PIKE_T_FUNCTION: if(func->subtype == FUNCTION_BUILTIN) break;
5a6d7d2001-04-10Fredrik Hübinette (Hubbe)  if(func->u.object->prog == pike_trampoline_program) { struct object *o; o=((struct pike_trampoline *)func->u.object->storage)->frame->current_object; add_ref(o); pop_n_elems(args); push_object(o); return; }
1c1c5e2001-04-08Fredrik Hübinette (Hubbe)  func->type=T_OBJECT; return;
5a6d7d2001-04-10Fredrik Hübinette (Hubbe)  default: SIMPLE_BAD_ARG_ERROR("function_object",1,"function");
1c1c5e2001-04-08Fredrik Hübinette (Hubbe)  } pop_n_elems(args); push_int(0); }
d95fa82001-06-05Fredrik Hübinette (Hubbe) /*! @decl int random(int max) *! *! This function returns a random number in the range 0 - @[max]-1. *! *! @seealso *! @[random_seed()] */
e1b4192001-06-06Fredrik Hübinette (Hubbe)  PIKEFUN mixed random(object o)
d95fa82001-06-05Fredrik Hübinette (Hubbe)  efun; optflags OPT_TRY_OPTIMIZE|OPT_EXTERNAL_DEPEND; {
e1b4192001-06-06Fredrik Hübinette (Hubbe)  apply(o,"_random",0); stack_swap(); pop_stack(); }
d95fa82001-06-05Fredrik Hübinette (Hubbe) 
e1b4192001-06-06Fredrik Hübinette (Hubbe) PIKEFUN int random(int i) { if(i <= 0) RETURN 0; RETURN my_rand() % i; } PIKEFUN float random(float f) { if(f<=0.0) RETURN 0.0;
d95fa82001-06-05Fredrik Hübinette (Hubbe) #define N 1048576
e1b4192001-06-06Fredrik Hübinette (Hubbe)  RETURN f * (my_rand()%N/((float)N)) + f * (my_rand()%N/( ((float)N) * ((float)N) ));
d95fa82001-06-05Fredrik Hübinette (Hubbe) 
e1b4192001-06-06Fredrik Hübinette (Hubbe) }
d95fa82001-06-05Fredrik Hübinette (Hubbe) 
e1b4192001-06-06Fredrik Hübinette (Hubbe) PIKEFUN mixed random(array a) { 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(); }
d95fa82001-06-05Fredrik Hübinette (Hubbe) 
e1b4192001-06-06Fredrik Hübinette (Hubbe) PIKEFUN mixed random(multiset m) { if(!m->ind->size) SIMPLE_BAD_ARG_ERROR("random", 1, "multiset with elements in it"); push_svalue(m->ind->item + (my_rand() % m->ind->size)); stack_swap(); pop_stack(); }
d95fa82001-06-05Fredrik Hübinette (Hubbe) 
e1b4192001-06-06Fredrik Hübinette (Hubbe) PIKEFUN mapping random(mapping m) { struct mapping_data *md=m->data; size_t bucket, count; struct keypair *k; if(!m_sizeof(m)) SIMPLE_BAD_ARG_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 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 */ push_svalue(&k->ind); push_svalue(&k->val); f_aggregate(2); stack_swap(); pop_stack();
d95fa82001-06-05Fredrik Hübinette (Hubbe) }
d27df52001-06-18Henrik Grubbström (Grubba) /* * Backtrace handling. */ /*! @class BacktraceFrame */ PIKECLASS backtrace_frame {
f61a482001-06-19Henrik Grubbström (Grubba)  PIKEVAR mixed fun;
2aca9f2001-06-19Henrik Grubbström (Grubba)  PIKEVAR array args;
de395b2001-06-19Henrik Grubbström (Grubba)  CVAR struct program *prog; /* FIXME: Ought to be a private pikevar... */
0f47db2001-06-19Henrik Grubbström (Grubba)  CVAR unsigned char *pc;
d27df52001-06-18Henrik Grubbström (Grubba)  CVAR struct pike_string *filename;
2aca9f2001-06-19Henrik Grubbström (Grubba)  CVAR INT_TYPE lineno;
d27df52001-06-18Henrik Grubbström (Grubba)  INIT {
0f47db2001-06-19Henrik Grubbström (Grubba)  THIS->fun.type = T_INT;
f61a482001-06-19Henrik Grubbström (Grubba)  THIS->fun.u.integer = 0;
0f47db2001-06-19Henrik Grubbström (Grubba)  THIS->prog = NULL; THIS->pc = 0;
d27df52001-06-18Henrik Grubbström (Grubba)  THIS->lineno = 0;
0f47db2001-06-19Henrik Grubbström (Grubba)  THIS->args = NULL; THIS->filename = NULL;
d27df52001-06-18Henrik Grubbström (Grubba)  } EXIT {
0f47db2001-06-19Henrik Grubbström (Grubba)  if (THIS->prog) { free_program(THIS->prog); THIS->prog = NULL; } if (THIS->args) { free_array(THIS->args); THIS->args = NULL;
d27df52001-06-18Henrik Grubbström (Grubba)  } if (THIS->filename) { free_string(THIS->filename);
0f47db2001-06-19Henrik Grubbström (Grubba)  THIS->filename = NULL;
d27df52001-06-18Henrik Grubbström (Grubba)  }
1073bf2001-06-26Henrik Grubbström (Grubba)  THIS->pc = NULL;
d27df52001-06-18Henrik Grubbström (Grubba)  THIS->lineno = 0;
0f47db2001-06-19Henrik Grubbström (Grubba)  free_svalue(&THIS->fun); THIS->fun.type = T_INT;
de395b2001-06-19Henrik Grubbström (Grubba)  THIS->fun.u.integer = 0;
d27df52001-06-18Henrik Grubbström (Grubba)  }
d2cd4e2001-06-18Henrik Grubbström (Grubba)  PIKEFUN int(0..1) _is_type(string t) { INT_TYPE res = (t == findstring("array")); pop_n_elems(args); push_int(res); }
d27df52001-06-18Henrik Grubbström (Grubba)  PIKEFUN string _sprintf(int c, mapping|void opts) { pop_n_elems(args); push_text("backtrace_frame(");
0f47db2001-06-19Henrik Grubbström (Grubba)  if (THIS->pc) {
d27df52001-06-18Henrik Grubbström (Grubba)  if (!THIS->filename) { THIS->filename =
0f47db2001-06-19Henrik Grubbström (Grubba)  make_shared_string(get_line(THIS->pc, THIS->prog, &THIS->lineno));
d27df52001-06-18Henrik Grubbström (Grubba)  }
1073bf2001-06-26Henrik Grubbström (Grubba)  THIS->pc = NULL; } if (THIS->prog) { free_program(THIS->prog); THIS->prog = NULL; } if (THIS->filename) {
d27df52001-06-18Henrik Grubbström (Grubba)  ref_push_string(THIS->filename); push_text(":"); push_int(THIS->lineno); push_text(", "); f_add(4); } else { push_text("Unknown file, "); }
0f47db2001-06-19Henrik Grubbström (Grubba)  if (THIS->fun.type == PIKE_T_FUNCTION) { if (THIS->fun.u.object->prog) { push_svalue(&THIS->fun); f_function_name(1); push_text("(), "); f_add(2); } else { free_svalue(&THIS->fun); THIS->fun.type = PIKE_T_INT; THIS->fun.u.integer = 0; THIS->fun.subtype = NUMBER_DESTRUCTED; push_text("destructed_function(), "); }
d27df52001-06-18Henrik Grubbström (Grubba)  } else { push_text("destructed_function(), "); }
0f47db2001-06-19Henrik Grubbström (Grubba)  if (THIS->args) {
d27df52001-06-18Henrik Grubbström (Grubba)  push_text("Args: ");
0f47db2001-06-19Henrik Grubbström (Grubba)  push_int(THIS->args->size);
d27df52001-06-18Henrik Grubbström (Grubba)  f_add(2); } else { push_text("No args"); } push_text(")"); f_add(5); } PIKEFUN int _sizeof() {
0f47db2001-06-19Henrik Grubbström (Grubba)  if (THIS->args) { push_int(THIS->args->size + 3); } else { push_int(3);
d27df52001-06-18Henrik Grubbström (Grubba)  } }
d2cd4e2001-06-18Henrik Grubbström (Grubba)  PIKEFUN mixed `[](int index, int|void end_or_none)
d27df52001-06-18Henrik Grubbström (Grubba)  {
d2cd4e2001-06-18Henrik Grubbström (Grubba)  INT_TYPE end = index; INT32 numargs = 0; INT32 i;
0f47db2001-06-19Henrik Grubbström (Grubba)  if (THIS->args) { numargs = THIS->args->size;
d27df52001-06-18Henrik Grubbström (Grubba)  }
d2cd4e2001-06-18Henrik Grubbström (Grubba)  numargs += 3; if (!end_or_none) { if (index < 0) { index_error("pike_frame->`[]", Pike_sp-args, 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, "Indexing with too large index (%"PRINTPIKEINT"d)\n", index); } } else { if (end_or_none->type != PIKE_T_INT) { SIMPLE_BAD_ARG_ERROR("`[]",2,"int|void"); } end = end_or_none->u.integer;
d27df52001-06-18Henrik Grubbström (Grubba)  } pop_n_elems(args);
d2cd4e2001-06-18Henrik Grubbström (Grubba)  if (end_or_none) {
0f47db2001-06-19Henrik Grubbström (Grubba)  if ((end < 0) || (end < index) || (index >= numargs)) {
d2cd4e2001-06-18Henrik Grubbström (Grubba)  f_aggregate(0); return;
d27df52001-06-18Henrik Grubbström (Grubba)  }
d2cd4e2001-06-18Henrik Grubbström (Grubba)  if (end >= numargs) { end = numargs-1;
d27df52001-06-18Henrik Grubbström (Grubba)  }
d2cd4e2001-06-18Henrik Grubbström (Grubba)  } for (i = index; i <= end; i++) { switch(i) { case 0: /* Filename */ case 1: /* Linenumber */
0f47db2001-06-19Henrik Grubbström (Grubba)  if (THIS->pc) {
d2cd4e2001-06-18Henrik Grubbström (Grubba)  if (!THIS->filename) { THIS->filename =
0f47db2001-06-19Henrik Grubbström (Grubba)  make_shared_string(get_line(THIS->pc, THIS->prog,
d2cd4e2001-06-18Henrik Grubbström (Grubba)  &THIS->lineno)); }
1073bf2001-06-26Henrik Grubbström (Grubba)  THIS->pc = NULL; } if (THIS->prog) { free_program(THIS->prog); THIS->prog = NULL; } if (i) { /* Linenumber */
d2cd4e2001-06-18Henrik Grubbström (Grubba)  push_int(THIS->lineno); } else {
1073bf2001-06-26Henrik Grubbström (Grubba)  /* Filename */ if (THIS->filename) { ref_push_string(THIS->filename); } else { push_int(0); }
d2cd4e2001-06-18Henrik Grubbström (Grubba)  }
1073bf2001-06-26Henrik Grubbström (Grubba)  break;
d2cd4e2001-06-18Henrik Grubbström (Grubba)  case 2: /* Function */
0f47db2001-06-19Henrik Grubbström (Grubba)  push_svalue(&THIS->fun);
d2cd4e2001-06-18Henrik Grubbström (Grubba)  break; default: /* Arguments */ {
0f47db2001-06-19Henrik Grubbström (Grubba)  if ((i > 2) && (THIS->args) && (i-3 < THIS->args->size)) { push_svalue(THIS->args->item + (i - 3));
d2cd4e2001-06-18Henrik Grubbström (Grubba)  break; } bad_arg_error("backtrace_frame->`[]", Pike_sp-args, args, 1, "int(0..)", Pike_sp-args, "Bad argument 1 to backtrace_frame->`[](): " "Expected int(0..%d)\n", numargs + 2); } /* NOT_REACHED */ break;
d27df52001-06-18Henrik Grubbström (Grubba)  }
d2cd4e2001-06-18Henrik Grubbström (Grubba)  } if (end_or_none) { f_aggregate(1 + end - index);
d27df52001-06-18Henrik Grubbström (Grubba)  } }
d2cd4e2001-06-18Henrik Grubbström (Grubba) 
1073bf2001-06-26Henrik Grubbström (Grubba)  PIKEFUN mixed `[]=(int index, mixed value) { INT32 numargs = 0; INT32 i; 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, "Index %"PRINTPIKEINT"d is out of array range 0 - %d,\n", index, numargs-1); } else if (index < 0) { index += numargs; } if (args > 2) { pop_n_elems(args - 2); args = 2; } switch(index) { case 0: /* Filename */ case 1: /* Linenumber */ /* First make sure we have line-number info. */ if (THIS->pc) { if (!THIS->filename) { THIS->filename = make_shared_string(get_line(THIS->pc, THIS->prog, &THIS->lineno)); } THIS->pc = NULL; } if (THIS->prog) { free_program(THIS->prog); THIS->prog = NULL; } if (index) { /* Linenumber */ if (value->type != PIKE_T_INT) { SIMPLE_BAD_ARG_ERROR("backtrace_frame->`[]=", 2, "int(1..)"); } THIS->lineno = value->u.integer; } else { /* Filename */ if (value->type != PIKE_T_STRING) { if ((value->type != PIKE_T_INT) || (value->u.integer)) { SIMPLE_BAD_ARG_ERROR("backtrace_frame->`[]=", 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 2: /* Function */ assign_svalue(&THIS->fun, value); break; default: /* Arguments */ assign_svalue(THIS->args->item + index - 3, value); break; } stack_swap(); pop_stack(); }
d27df52001-06-18Henrik Grubbström (Grubba) }; /*! @endclass */
91d3972001-06-19Henrik Grubbström (Grubba) /*! @decl array(array) backtrace() *! *! Get a description of the current call stack. *! *! The description is returned as an array with one entry for each call *! frame on the stack. *! *! Each entry has this format: *! @array *! @elem string file *! A string with the filename if known, else zero. *! @elem int line *! An integer containing the linenumber if known, else zero. *! @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 accomodate 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()]
d27df52001-06-18Henrik Grubbström (Grubba)  */
91d3972001-06-19Henrik Grubbström (Grubba) PMOD_EXPORT PIKEFUN array(mixed) backtrace() efun; optflags OPT_EXTERNAL_DEPEND;
d27df52001-06-18Henrik Grubbström (Grubba) {
c98dd22001-06-26Martin Stjernholm  struct pike_frame *f, *of = 0;
d27df52001-06-18Henrik Grubbström (Grubba)  int size = 0;
9906e32001-06-20Henrik Grubbström (Grubba)  struct array *res = NULL;
d27df52001-06-18Henrik Grubbström (Grubba) 
a3b6b02001-06-19Henrik Grubbström (Grubba)  for (f = Pike_fp; f; f = f->next) {
9906e32001-06-20Henrik Grubbström (Grubba)  size++; } res = allocate_array_no_init(size, 0); push_array(res);
c98dd22001-06-26Martin Stjernholm  for (f = Pike_fp; f && size; f = (of = f)->next) {
d27df52001-06-18Henrik Grubbström (Grubba)  struct object *o = low_clone(backtrace_frame_program);
0f47db2001-06-19Henrik Grubbström (Grubba)  struct backtrace_frame_struct *bf;
d27df52001-06-18Henrik Grubbström (Grubba)  call_c_initializers(o);
0f47db2001-06-19Henrik Grubbström (Grubba) 
9906e32001-06-20Henrik Grubbström (Grubba)  size--; res->item[size].u.object = o; res->item[size].type = PIKE_T_OBJECT; res->item[size].subtype = 0;
0f47db2001-06-19Henrik Grubbström (Grubba)  bf = OBJ2_BACKTRACE_FRAME(o); if ((bf->prog = f->context.prog)) { add_ref(bf->prog); bf->pc = f->pc; } if ((bf->fun.u.object = f->current_object) && (bf->fun.u.object->prog)) { add_ref(bf->fun.u.object); bf->fun.subtype = f->fun; bf->fun.type = PIKE_T_FUNCTION; } else { bf->fun.u.integer = 0; bf->fun.subtype = NUMBER_DESTRUCTED; bf->fun.type = PIKE_T_INT; } if (f->locals) { INT32 numargs = DO_NOT_WARN((INT32) MINIMUM(f->num_args, Pike_sp - f->locals));
c98dd22001-06-26Martin Stjernholm  if(of) /* f->num_args can be too large, so this is necessary for some * reason. I don't know why. /mast */ numargs = DO_NOT_WARN((INT32)MINIMUM(f->num_args,of->locals - f->locals));
0f47db2001-06-19Henrik Grubbström (Grubba)  numargs = MAXIMUM(numargs, 0); if (numargs) { bf->args = allocate_array_no_init(numargs, 0); assign_svalues_no_free(bf->args->item, f->locals, numargs, BIT_MIXED); } }
d27df52001-06-18Henrik Grubbström (Grubba)  }
9906e32001-06-20Henrik Grubbström (Grubba)  /* NOTE: res has already been pushed on the stack. */
d27df52001-06-18Henrik Grubbström (Grubba) }
e1b4192001-06-06Fredrik Hübinette (Hubbe) 
a3c4332001-06-20Per Hedbor #define INITIAL_BUF_LEN 4096 /*! @module String */ PIKECLASS Buffer /*! @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 *! @} */ {
73b07a2001-06-21Per Hedbor  CVAR struct string_builder str; CVAR int initial;
a3c4332001-06-20Per Hedbor  void f_Buffer_get_copy( INT32 args ); void f_Buffer_get( INT32 args ); void f_Buffer_add( INT32 args ); PIKEFUN void create( int|void size )
73b07a2001-06-21Per Hedbor  /*! @decl void create()
a3c4332001-06-20Per Hedbor  *! *! Initializes a new buffer.
73b07a2001-06-21Per Hedbor  *!
a3c4332001-06-20Per Hedbor  *! If no @[initial_size] is specified, 4096 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. */ { struct Buffer_struct *str = THIS; if( args ) str->initial = MAXIMUM( size->u.integer, 512 ); else {
73b07a2001-06-21Per Hedbor  str->initial = 256;
a3c4332001-06-20Per Hedbor  push_int(0); } } 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 */)" );
73b07a2001-06-21Per Hedbor  if( str->str.s )
a3c4332001-06-20Per Hedbor  {
73b07a2001-06-21Per Hedbor  push_int(str->str.s->len); push_int(str->str.malloced);
a3c4332001-06-20Per Hedbor  } else { push_int( 0 ); push_int( 0 ); } f_sprintf( 3 ); 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_int( 0 ); Pike_sp[-1].subtype = 1; } PIKEFUN mixed cast( string type ) { struct pike_string *string_t; struct pike_string *int_t; MAKE_CONSTANT_SHARED_STRING( string_t, "string" ); MAKE_CONSTANT_SHARED_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->str ); } PIKEFUN object `+( string what ) { struct Buffer_struct *str = THIS, *str2; struct object *res = clone_object( Buffer_program, 0 );
73b07a2001-06-21Per Hedbor  if( str->str.s ) { str2 = OBJ2_BUFFER( res ); if( str2->str.s ) free_string_builder( &str2->str ); *str2 = *str; init_string_builder_alloc( &str2->str, str->str.malloced, str->str.s->size_shift ); MEMCPY( (void *)str2->str.s, (void *)str->str.s, str->str.malloced+sizeof(struct pike_string)); }
a3c4332001-06-20Per Hedbor  apply( res, "add", 1 ); RETURN res; } PIKEFUN object `+=( string what ) { f_Buffer_add( 1 ); REF_RETURN fp->current_object; }
3301b12001-06-20Per Hedbor  PIKEFUN int add( string ... arg1 ) /*! @decl void add(string ... data)
a3c4332001-06-20Per Hedbor  *! *! Adds @[data] to the buffer. Returns the size of the buffer. *! */ { struct Buffer_struct *str = THIS;
3301b12001-06-20Per Hedbor  int j; struct pike_string *a;
a3c4332001-06-20Per Hedbor 
3301b12001-06-20Per Hedbor  for( j = 0; j<args; j++ )
a3c4332001-06-20Per Hedbor  {
3301b12001-06-20Per Hedbor  a = Pike_sp[-args+j].u.string;
73b07a2001-06-21Per Hedbor  if( !str->str.s ) init_string_builder_alloc( &str->str, str->initial, a->size_shift ); string_builder_shared_strcat( &str->str, a );
3301b12001-06-20Per Hedbor  }
73b07a2001-06-21Per Hedbor  RETURN str->str.s->len;
a3c4332001-06-20Per Hedbor  } PIKEFUN string get_copy() /*! @decl string get_copy() *! *! Get the data from the buffer. Significantly slower than @[get], *! but does not clear the buffer. */ {
73b07a2001-06-21Per Hedbor  struct pike_string *str = THIS->str.s; if( str )
a3c4332001-06-20Per Hedbor  {
73b07a2001-06-21Per Hedbor  ptrdiff_t len = str->len; if( len > 0 ) { char *d = (char *)str->str; switch( str->size_shift ) { case 0: RETURN make_shared_binary_string(d,len); break; case 1: RETURN make_shared_binary_string1((short*)d,len>>1); break; case 2: RETURN make_shared_binary_string2((int*)d,len>>2); break; } }
a3c4332001-06-20Per Hedbor  }
73b07a2001-06-21Per Hedbor  push_text(""); return;
a3c4332001-06-20Per Hedbor  } PIKEFUN string get( ) /*! @decl string get() *! *! Get the data from the buffer. *! *! @note *! This will clear the data in the buffer */ { struct Buffer_struct *str = THIS;
73b07a2001-06-21Per Hedbor  if( str->str.s )
a3c4332001-06-20Per Hedbor  {
73b07a2001-06-21Per Hedbor  struct pike_string *s = finish_string_builder( &str->str ); str->str.malloced = 0; str->str.s = 0; RETURN s;
a3c4332001-06-20Per Hedbor  }
73b07a2001-06-21Per Hedbor  pop_n_elems(args); push_text(""); return;
a3c4332001-06-20Per Hedbor  } INIT { struct Buffer_struct *str = THIS;
73b07a2001-06-21Per Hedbor  MEMSET( str, 0, sizeof( *str ) );
a3c4332001-06-20Per Hedbor  } EXIT { struct Buffer_struct *str = THIS;
73b07a2001-06-21Per Hedbor  if( str->str.s ) free_string_builder( &str->str );
a3c4332001-06-20Per Hedbor  } }
fed7de2001-06-28Henrik Grubbström (Grubba) /*! @endmodule */ /*! @module String */ /*! @class Replace */ PIKECLASS multi_string_replace { CVAR struct tupel { int prefix; struct pike_string *ind; struct pike_string *val; } *v; CVAR size_t v_sz; CVAR size_t sz; CVAR INT32 set_start[256]; CVAR INT32 set_end[256]; static int replace_sortfun(struct tupel *a,struct tupel *b) { return DO_NOT_WARN((int)my_quick_strcmp(a->ind, b->ind)); }
f01b122001-07-01Henrik Grubbström (Grubba)  PIKEFUN void create(array(string)|void from_, array(string)|void to_)
fed7de2001-06-28Henrik Grubbström (Grubba)  { int i;
f01b122001-07-01Henrik Grubbström (Grubba)  struct array *from; struct array *to; if (!args) { push_int(0); return; } if (!from_ || !to_) { Pike_error("Bad number of arguments to create().\n"); } from = from_->u.array; to = to_->u.array;
fed7de2001-06-28Henrik Grubbström (Grubba)  if (from->size != to->size) { Pike_error("Replace must have equal-sized from and to arrays.\n"); } for (i = 0; i < (int)from->size; i++) { if (from->item[i].type != PIKE_T_STRING) { Pike_error("Replace: from array is not an array(string).\n"); } if (to->item[i].type != PIKE_T_STRING) { Pike_error("Replace: to array is not an array(string).\n"); } } if (THIS->v) { for (i = 0; i < (int)THIS->v_sz; i++) { if (!THIS->v[i].ind) break; free_string(THIS->v[i].ind); THIS->v[i].ind = NULL; free_string(THIS->v[i].val); THIS->v[i].val = NULL; } } if (THIS->v && (THIS->v_sz < (size_t)from->size)) { free(THIS->v); THIS->v = NULL; THIS->v_sz = 0; } if (!THIS->v) { THIS->v = (struct tupel *)xalloc(sizeof(struct tupel) * from->size); THIS->v_sz = from->size; } for (i = 0; i < (int)from->size; i++) { copy_shared_string(THIS->v[i].ind, from->item[i].u.string); copy_shared_string(THIS->v[i].val, to->item[i].u.string); THIS->v[i].prefix = -2; /* Uninitialized */ } THIS->sz = from->size; fsort((char *)THIS->v, from->size, sizeof(struct tupel), (fsortfun)replace_sortfun); MEMSET(THIS->set_start, 0, sizeof(INT32)*256); MEMSET(THIS->set_end, 0, sizeof(INT32)*256); for (i = 0; i < (int)from->size; i++) { INT32 x = index_shared_string(THIS->v[from->size-1-i].ind, 0); if ((x >= 0) && (x < 256)) THIS->set_start[x] = from->size-1-i; x = index_shared_string(THIS->v[i].ind, 0); if ((x >= 0) && (x < 256)) THIS->set_end[x] = i+1; }
f01b122001-07-01Henrik Grubbström (Grubba)  pop_n_elems(args); push_int(0);
fed7de2001-06-28Henrik Grubbström (Grubba)  } static int find_longest_prefix(char *str, ptrdiff_t len, int size_shift, struct tupel *v, INT32 a, INT32 b) { INT32 c,match=-1; ptrdiff_t tmp; while(a<b) { c=(a+b)/2; tmp=generic_quick_binary_strcmp(v[c].ind->str, v[c].ind->len, v[c].ind->size_shift, str, MINIMUM(len,v[c].ind->len), size_shift); if(tmp<0) { INT32 match2=find_longest_prefix(str, len, size_shift, v, c+1, b); if(match2!=-1) return match2; while(1) { if(v[c].prefix==-2) { v[c].prefix=find_longest_prefix(v[c].ind->str, v[c].ind->len, v[c].ind->size_shift, v, 0 /* can this be optimized? */, c); } c=v[c].prefix; if(c<a || c<match) return match; if(!generic_quick_binary_strcmp(v[c].ind->str, v[c].ind->len, v[c].ind->size_shift, str, MINIMUM(len,v[c].ind->len), size_shift)) return c; } } else if(tmp>0) { b=c; } else { a=c+1; /* There might still be a better match... */ match=c; } } return match; } PIKEFUN string `()(string str) { struct string_builder ret; ptrdiff_t length = str->len; ptrdiff_t s; int *set_start = THIS->set_start; int *set_end = THIS->set_end; struct tupel *v = THIS->v; int num = THIS->sz; if (!num) { add_ref(str); RETURN str; } init_string_builder(&ret,str->size_shift); for(s=0;length > 0;) { INT32 a,b; ptrdiff_t ch; ch = index_shared_string(str, s); if((ch >= 0) && (ch < 256)) b = set_end[ch]; else b = num; if(b) { if((ch >= 0) && (ch < 256)) a = set_start[ch]; else a = 0; a = find_longest_prefix(str->str+(s << str->size_shift), length, str->size_shift, v, a, b); if(a!=-1) { ch = v[a].ind->len; if(!ch) ch=1; s += ch; length -= ch; string_builder_shared_strcat(&ret, v[a].val); continue; } } string_builder_putchar(&ret, DO_NOT_WARN((INT32)ch)); s++; length--; } RETURN finish_string_builder(&ret); }
9f91572001-07-01Henrik Grubbström (Grubba)  PIKEFUN array(string) _encode() { size_t i; for (i=0; i < THIS->sz; i++) { ref_push_string(THIS->v[i].ind); } f_aggregate(DO_NOT_WARN((INT32)THIS->sz)); for (i=0; i < THIS->sz; i++) { ref_push_string(THIS->v[i].val); } f_aggregate(DO_NOT_WARN((INT32)THIS->sz)); f_aggregate(2); } PIKEFUN void _decode(array(array(string)) encoded) { INT32 i; for (i=0; i < encoded->size; i++) { push_svalue(encoded->item + i); stack_swap(); } pop_stack(); f_multi_string_replace_create(i); }
fed7de2001-06-28Henrik Grubbström (Grubba)  INIT { THIS->v = NULL; THIS->v_sz = 0; THIS->sz = 0; } EXIT { if (THIS->v) { int i; for (i = 0; i < (int)THIS->v_sz; i++) { if (!THIS->v[i].ind) break; free_string(THIS->v[i].ind); THIS->v[i].ind = NULL; free_string(THIS->v[i].val); THIS->v[i].val = NULL; } free(THIS->v); } THIS->v = NULL; THIS->v_sz = 0; THIS->sz = 0; } } /*! @endclass */ /*! @endmodule */
a3c4332001-06-20Per Hedbor 
3a5b1d2000-05-24Fredrik Hübinette (Hubbe) void init_builtin(void) {
ab82822000-05-25Fredrik Hübinette (Hubbe) INIT
3a5b1d2000-05-24Fredrik Hübinette (Hubbe) }
8650752001-06-25Henrik Grubbström (Grubba)  void exit_builtin(void) { EXIT }