e576bb2002-10-11Martin Nilsson /* || 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.
b2630d2004-05-20Henrik Grubbström (Grubba) || $Id: builtin_functions.c,v 1.558 2004/05/20 20:13:38 grubba Exp $
e576bb2002-10-11Martin Nilsson */
aedfb12002-10-09Martin Nilsson 
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "global.h"
b2630d2004-05-20Henrik Grubbström (Grubba) RCSID("$Id: builtin_functions.c,v 1.558 2004/05/20 20:13:38 grubba Exp $");
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "interpret.h" #include "svalue.h"
bb55f81997-03-16Fredrik Hübinette (Hubbe) #include "pike_macros.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "object.h" #include "program.h" #include "array.h"
b2d3e42000-12-01Fredrik Hübinette (Hubbe) #include "pike_error.h"
06983f1996-09-22Fredrik Hübinette (Hubbe) #include "constants.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "mapping.h" #include "stralloc.h"
06983f1996-09-22Fredrik Hübinette (Hubbe) #include "multiset.h" #include "pike_types.h"
66bcf02002-12-07Henrik Grubbström (Grubba) #include "pike_rusage.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "operators.h" #include "fsort.h" #include "callback.h"
624d091996-02-24Fredrik Hübinette (Hubbe) #include "gc.h"
ed70b71996-06-09Fredrik Hübinette (Hubbe) #include "backend.h" #include "main.h"
9aa6fa1997-05-19Fredrik Hübinette (Hubbe) #include "pike_memory.h"
07513e1996-10-04Fredrik Hübinette (Hubbe) #include "threads.h"
3beb891996-06-21Fredrik Hübinette (Hubbe) #include "time_stuff.h"
6023ae1997-01-18Fredrik Hübinette (Hubbe) #include "version.h"
aac0151997-01-26Fredrik Hübinette (Hubbe) #include "encode.h"
3beb891996-06-21Fredrik Hübinette (Hubbe) #include <math.h>
38bddc1996-08-12Fredrik Hübinette (Hubbe) #include <ctype.h>
32a9581997-01-31Fredrik Hübinette (Hubbe) #include "module_support.h"
9c6f7d1997-04-15Fredrik Hübinette (Hubbe) #include "module.h" #include "opcodes.h"
fc33451997-10-02Fredrik Hübinette (Hubbe) #include "cyclic.h"
89b0721998-05-05Fredrik Hübinette (Hubbe) #include "signal_handler.h"
37775c2004-04-06Martin Nilsson #include "pike_security.h"
c1073a1999-05-11Mirar (Pontus Hagland) #include "builtin_functions.h"
39ac731999-10-20Fredrik Noring #include "bignum.h"
629c5e2001-08-31Martin Stjernholm #include "peep.h"
0811472001-07-02Fredrik Hübinette (Hubbe) #include "docode.h" #include "lex.h"
a63b362003-11-07Martin Stjernholm #include "pike_float.h"
6930181996-02-25Fredrik Hübinette (Hubbe) 
8bee431998-04-01Henrik Grubbström (Grubba) #ifdef HAVE_POLL
df284f1998-04-29Henrik Grubbström (Grubba) #ifdef HAVE_POLL_H
8bee431998-04-01Henrik Grubbström (Grubba) #include <poll.h>
df284f1998-04-29Henrik Grubbström (Grubba) #endif /* HAVE_POLL_H */ #ifdef HAVE_SYS_POLL_H #include <sys/poll.h> #endif /* HAVE_SYS_POLL_H */
8bee431998-04-01Henrik Grubbström (Grubba) #endif /* HAVE_POLL */
5267b71995-08-09Fredrik Hübinette (Hubbe) #ifdef HAVE_CRYPT_H #include <crypt.h> #endif
8fe8101998-03-16Henrik Grubbström (Grubba) /* #define DIFF_DEBUG */
92bb061998-05-19Henrik Grubbström (Grubba) /* #define ENABLE_DYN_DIFF */
38bddc1996-08-12Fredrik Hübinette (Hubbe) 
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl int equal(mixed a, mixed b) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function checks if the values @[a] and @[b] are equal.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! For all types but arrays, multisets and mappings, this operation is
f79bd82003-04-01Martin Nilsson  *! the same as doing @expr{@[a] == @[b]@}.
554e222001-05-06Henrik Grubbström (Grubba)  *! For arrays, mappings and multisets however, their contents are checked *! recursively, and if all their contents are the same and in the same *! place, they are considered equal.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[copy_value()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_equal(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) { int i;
7cc8311998-04-10Henrik Grubbström (Grubba)  if(args != 2)
7c9e8a2003-01-04Martin Nilsson  SIMPLE_TOO_FEW_ARGS_ERROR("equal", 2);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  i=is_equal(Pike_sp-2,Pike_sp-1);
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_int(i); }
7535f82001-01-08Henrik Grubbström (Grubba) /*! @decl array aggregate(mixed ... elements)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Construct an array with the arguments as indices.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function could be written in Pike as:
f79bd82003-04-01Martin Nilsson  *! @code *! array aggregate(mixed ... elems) { return elems; } *! @endcode
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @note
554e222001-05-06Henrik Grubbström (Grubba)  *! Arrays are dynamically allocated there is no need to declare them
f79bd82003-04-01Martin Nilsson  *! like @expr{int a[10]=allocate(10);@} (and it isn't possible either) like *! in C, just @expr{array(int) a=allocate(10);@} will do.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[sizeof()], @[arrayp()], @[allocate()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void debug_f_aggregate(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) { struct array *a;
99946c1996-02-17Fredrik Hübinette (Hubbe)  a=aggregate_array(args);
5267b71995-08-09Fredrik Hübinette (Hubbe)  push_array(a); /* beware, macro */ }
0811472001-07-02Fredrik Hübinette (Hubbe) 
5d98c42003-03-02Henrik Grubbström (Grubba) /*! @decl int hash_7_4(string s) *! @decl int hash_7_4(string s, int max) *!
5ad0962003-11-10Martin Stjernholm  *! Return an integer derived from the string @[s]. The same string *! will always hash to the same value, also between processes. *! *! If @[max] is given, the result will be >= 0 and < @[max], *! otherwise the result will be >= 0 and <= 0x7fffffff.
5d98c42003-03-02Henrik Grubbström (Grubba)  *! *! @note *! This function is provided for backward compatibility reasons. *!
5ad0962003-11-10Martin Stjernholm  *! This function is byte-order dependant for wide strings.
5d98c42003-03-02Henrik Grubbström (Grubba)  *! *! @seealso *! @[hash()], @[hash_7_0()] */ static void f_hash_7_4(INT32 args) { size_t i = 0; struct pike_string *s = Pike_sp[-args].u.string; if(!args) SIMPLE_TOO_FEW_ARGS_ERROR("hash_7_4",1); if(Pike_sp[-args].type != T_STRING) SIMPLE_BAD_ARG_ERROR("hash_7_4", 1, "string"); i = simple_hashmem((unsigned char *)s->str, s->len<<s->size_shift, 100<<s->size_shift); if(args > 1) { if(Pike_sp[1-args].type != T_INT) SIMPLE_BAD_ARG_ERROR("hash_7_4",2,"int"); if(!Pike_sp[1-args].u.integer) PIKE_ERROR("hash_7_4", "Modulo by zero.\n", Pike_sp, args); i%=(unsigned INT32)Pike_sp[1-args].u.integer; } pop_n_elems(args); push_int64(i); }
a056042001-10-28Martin Nilsson /*! @decl int hash_7_0(string s) *! @decl int hash_7_0(string s, int max)
ce4d672001-01-31Henrik Grubbström (Grubba)  *!
5ad0962003-11-10Martin Stjernholm  *! Return an integer derived from the string @[s]. The same string *! always hashes to the same value, also between processes. *! *! If @[max] is given, the result will be >= 0 and < @[max], *! otherwise the result will be >= 0 and <= 0x7fffffff.
ce4d672001-01-31Henrik Grubbström (Grubba)  *! *! @note *! This function is provided for backward compatibility reasons. *!
5d98c42003-03-02Henrik Grubbström (Grubba)  *! This function is not NUL-safe, and is byte-order dependant. *!
ce4d672001-01-31Henrik Grubbström (Grubba)  *! @seealso
5d98c42003-03-02Henrik Grubbström (Grubba)  *! @[hash()], @[hash_7_4()]
ce4d672001-01-31Henrik Grubbström (Grubba)  */
5d98c42003-03-02Henrik Grubbström (Grubba) static void f_hash_7_0( INT32 args )
348cff2000-12-11Per Hedbor { struct pike_string *s = Pike_sp[-args].u.string; unsigned int i; if(!args)
7c9e8a2003-01-04Martin Nilsson  SIMPLE_TOO_FEW_ARGS_ERROR("hash_7_0",1);
348cff2000-12-11Per Hedbor  if(Pike_sp[-args].type != T_STRING)
7c9e8a2003-01-04Martin Nilsson  SIMPLE_BAD_ARG_ERROR("hash_7_0", 1, "string");
348cff2000-12-11Per Hedbor  if( s->size_shift ) {
5d98c42003-03-02Henrik Grubbström (Grubba)  f_hash_7_4( args );
348cff2000-12-11Per Hedbor  return; }
986b522001-03-17Henrik Grubbström (Grubba)  i = DO_NOT_WARN((unsigned int)hashstr( (unsigned char *)s->str, MINIMUM(100,s->len)));
348cff2000-12-11Per Hedbor  if(args > 1) { if(Pike_sp[1-args].type != T_INT)
7c9e8a2003-01-04Martin Nilsson  SIMPLE_BAD_ARG_ERROR("hash_7_0",2,"int");
348cff2000-12-11Per Hedbor  if(!Pike_sp[1-args].u.integer)
7c9e8a2003-01-04Martin Nilsson  PIKE_ERROR("hash_7_0", "Modulo by zero.\n", Pike_sp, args);
348cff2000-12-11Per Hedbor  i%=(unsigned INT32)Pike_sp[1-args].u.integer; } pop_n_elems(args); push_int( i ); }
5267b71995-08-09Fredrik Hübinette (Hubbe) 
ce4d672001-01-31Henrik Grubbström (Grubba) /*! @decl int hash(string s) *! @decl int hash(string s, int max) *!
5ad0962003-11-10Martin Stjernholm  *! Return an integer derived from the string @[s]. The same string *! always hashes to the same value, also between processes, *! architectures, and Pike versions (see compatibility notes below, *! though). *! *! If @[max] is given, the result will be >= 0 and < @[max], *! otherwise the result will be >= 0 and <= 0x7fffffff.
ce4d672001-01-31Henrik Grubbström (Grubba)  *! *! @note
5d98c42003-03-02Henrik Grubbström (Grubba)  *! The hash algorithm was changed in Pike 7.5. If you want a hash *! that is compatible with Pike 7.4 and earlier, use @[hash_7_4()].
5ad0962003-11-10Martin Stjernholm  *! The difference only affects wide strings.
5d98c42003-03-02Henrik Grubbström (Grubba)  *! *! The hash algorithm was also changed in Pike 7.1. If you want a hash
a056042001-10-28Martin Nilsson  *! that is compatible with Pike 7.0 and earlier, use @[hash_7_0()].
ce4d672001-01-31Henrik Grubbström (Grubba)  *! *! @seealso
5ad0962003-11-10Martin Stjernholm  *! @[hash_7_0()], @[hash_7_4()], @[hash_value]
ce4d672001-01-31Henrik Grubbström (Grubba)  */
5d98c42003-03-02Henrik Grubbström (Grubba) PMOD_EXPORT void f_hash(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
cb787a2000-08-24Henrik Grubbström (Grubba)  size_t i = 0;
5d98c42003-03-02Henrik Grubbström (Grubba)  struct pike_string *s;
93b7202000-08-14Henrik Grubbström (Grubba) 
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(!args)
8aefbc1999-03-19Fredrik Hübinette (Hubbe)  SIMPLE_TOO_FEW_ARGS_ERROR("hash",1);
98d8e72000-12-10Per Hedbor 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[-args].type != T_STRING)
8aefbc1999-03-19Fredrik Hübinette (Hubbe)  SIMPLE_BAD_ARG_ERROR("hash", 1, "string");
f285911999-03-09Fredrik Hübinette (Hubbe) 
5d98c42003-03-02Henrik Grubbström (Grubba)  s = Pike_sp[-args].u.string; switch(s->size_shift) { case 0: i = simple_hashmem(STR0(s), s->len, 100); break; case 1: i = simple_hashmem1(STR1(s), s->len, 100); break; case 2: i = simple_hashmem2(STR2(s), s->len, 100); break; default: Pike_fatal("hash(): Unsupported string shift: %d\n", s->size_shift); break; }
98d8e72000-12-10Per Hedbor 
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(args > 1) {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[1-args].type != T_INT)
8aefbc1999-03-19Fredrik Hübinette (Hubbe)  SIMPLE_BAD_ARG_ERROR("hash",2,"int");
5267b71995-08-09Fredrik Hübinette (Hubbe) 
c5ab042004-05-13Martin Nilsson  if(Pike_sp[1-args].u.integer <= 0) PIKE_ERROR("hash", "Modulo < 1.\n", Pike_sp, args);
5d98c42003-03-02Henrik Grubbström (Grubba) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  i%=(unsigned INT32)Pike_sp[1-args].u.integer;
5267b71995-08-09Fredrik Hübinette (Hubbe)  } pop_n_elems(args);
93b7202000-08-14Henrik Grubbström (Grubba)  push_int64(i);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
5ad0962003-11-10Martin Stjernholm /*! @decl int hash_value (mixed value) *! *! Return a hash value for the argument. It's an integer in the *! native integer range. *! *! The hash will be the same for the same value in the running *! process only (the memory address is typically used as the basis *! for the hash value). *! *! If the value is an object with an @[lfun::__hash], that function *! is called and its result is returned. *! *! @note *! This is the hashing method used by mappings. *! *! @seealso *! @[hash] */ void f_hash_value(INT32 args) { unsigned INT32 h; if(!args) SIMPLE_TOO_FEW_ARGS_ERROR("hash_value",1); h = hash_svalue (Pike_sp - args); pop_n_elems (args); push_int (h); }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl mixed copy_value(mixed value) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Copy a value recursively.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! If the result value is changed destructively (only possible for *! multisets, arrays and mappings) the copied value will not be changed.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! The resulting value will always be equal to the copied (as tested with *! the function @[equal()]), but they may not the the same value (as tested *! with @[`==()]).
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[equal()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_copy_value(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) { if(!args)
8aefbc1999-03-19Fredrik Hübinette (Hubbe)  SIMPLE_TOO_FEW_ARGS_ERROR("copy_value",1);
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args-1);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  copy_svalues_recursively_no_free(Pike_sp,Pike_sp-1,1,0); free_svalue(Pike_sp-1); Pike_sp[-1]=Pike_sp[0]; dmalloc_touch_svalue(Pike_sp-1);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
94d9921999-03-20Henrik Grubbström (Grubba) struct case_info {
9776dd2001-06-21Henrik Grubbström (Grubba)  INT32 low; /* low end of range. */ INT32 mode; INT32 data;
94d9921999-03-20Henrik Grubbström (Grubba) }; #define CIM_NONE 0 /* Case-less */
164d671999-03-20Henrik Grubbström (Grubba) #define CIM_UPPERDELTA 1 /* Upper-case, delta to lower-case in data */ #define CIM_LOWERDELTA 2 /* Lower-case, -delta to upper-case in data */
94d9921999-03-20Henrik Grubbström (Grubba) #define CIM_CASEBIT 3 /* Some case, case mask in data */ #define CIM_CASEBITOFF 4 /* Same as above, but also offset by data */
0cb4152000-07-19Andreas Lange static const struct case_info case_info[] = {
94d9921999-03-20Henrik Grubbström (Grubba) #include "case_info.h"
9776dd2001-06-21Henrik Grubbström (Grubba)  { 0x7fffffff, CIM_NONE, 0x0000, }, /* End sentinel. */
94d9921999-03-20Henrik Grubbström (Grubba) };
9776dd2001-06-21Henrik Grubbström (Grubba) static struct case_info *find_ci(INT32 c)
94d9921999-03-20Henrik Grubbström (Grubba) { static struct case_info *cache = NULL;
5e3f721999-03-20Per Hedbor  struct case_info *ci = cache;
94d9921999-03-20Henrik Grubbström (Grubba)  int lo = 0; int hi = NELEM(case_info);
9776dd2001-06-21Henrik Grubbström (Grubba)  if ((c < 0) || (c > 0xeffff)) { /* Negative, or plane 15 and above. */
94d9921999-03-20Henrik Grubbström (Grubba)  return NULL;
9776dd2001-06-21Henrik Grubbström (Grubba)  }
94d9921999-03-20Henrik Grubbström (Grubba)  if ((ci) && (ci[0].low <= c) && (ci[1].low > c)) {
480bf02000-07-27Andreas Lange  return ci;
94d9921999-03-20Henrik Grubbström (Grubba)  } while (lo != hi-1) { int mid = (lo + hi)/2; if (case_info[mid].low < c) { lo = mid; } else if (case_info[mid].low == c) { lo = mid; break; } else { hi = mid; } }
a8d36d2000-07-19Andreas Lange  return(cache = (struct case_info *)case_info + lo);
94d9921999-03-20Henrik Grubbström (Grubba) }
9776dd2001-06-21Henrik Grubbström (Grubba) static struct case_info *find_ci_shift0(INT32 c)
480bf02000-07-27Andreas Lange { static struct case_info *cache = NULL; struct case_info *ci = cache; int lo = 0; int hi = CASE_INFO_SHIFT0_HIGH;
9776dd2001-06-21Henrik Grubbström (Grubba)  if ((c < 0) || (c > 0xefffff)) { /* Negative, or plane 15 and above. */
480bf02000-07-27Andreas Lange  return NULL;
9776dd2001-06-21Henrik Grubbström (Grubba)  }
480bf02000-07-27Andreas Lange  if ((ci) && (ci[0].low <= c) && (ci[1].low > c)) { return ci; } while (lo != hi-1) { int mid = (lo + hi)>>1; if (case_info[mid].low < c) { lo = mid; } else if (case_info[mid].low == c) { lo = mid; break; } else { hi = mid; } } return(cache = (struct case_info *)case_info + lo); }
94d9921999-03-20Henrik Grubbström (Grubba) #define DO_LOWER_CASE(C) do {\
9776dd2001-06-21Henrik Grubbström (Grubba)  INT32 c = C; \
bd662f2004-04-12Per Hedbor  if(c<128){if(c >= 'A' && c <= 'Z' ) C=c+0x20;}else {\
3325952004-04-13Jonas Wallden  struct case_info *ci = find_ci(c); \
94d9921999-03-20Henrik Grubbström (Grubba)  if (ci) { \ switch(ci->mode) { \
164d671999-03-20Henrik Grubbström (Grubba)  case CIM_NONE: case CIM_LOWERDELTA: break; \ case CIM_UPPERDELTA: C = c + ci->data; break; \ case CIM_CASEBIT: C = c | ci->data; break; \
94d9921999-03-20Henrik Grubbström (Grubba)  case CIM_CASEBITOFF: C = ((c - ci->data) | ci->data) + ci->data; break; \
5aad932002-08-15Marcus Comstedt  default: Pike_fatal("lower_case(): Unknown case_info mode: %d\n", ci->mode); \
94d9921999-03-20Henrik Grubbström (Grubba)  } \
bd662f2004-04-12Per Hedbor  }} \
94d9921999-03-20Henrik Grubbström (Grubba)  } while(0)
480bf02000-07-27Andreas Lange #define DO_LOWER_CASE_SHIFT0(C) do {\
9776dd2001-06-21Henrik Grubbström (Grubba)  INT32 c = C; \
bd662f2004-04-12Per Hedbor  if(c<128){if(c >= 'A' && c <= 'Z' ) C=c+0x20;}else {\
480bf02000-07-27Andreas Lange  struct case_info *ci = find_ci_shift0(c); \ if (ci) { \ switch(ci->mode) { \ case CIM_NONE: case CIM_LOWERDELTA: break; \ case CIM_UPPERDELTA: C = c + ci->data; break; \ case CIM_CASEBIT: C = c | ci->data; break; \ case CIM_CASEBITOFF: C = ((c - ci->data) | ci->data) + ci->data; break; \
5aad932002-08-15Marcus Comstedt  default: Pike_fatal("lower_case(): Unknown case_info mode: %d\n", ci->mode); \
480bf02000-07-27Andreas Lange  } \
bd662f2004-04-12Per Hedbor  }} \
480bf02000-07-27Andreas Lange  } while(0)
94d9921999-03-20Henrik Grubbström (Grubba) #define DO_UPPER_CASE(C) do {\
9776dd2001-06-21Henrik Grubbström (Grubba)  INT32 c = C; \
bd662f2004-04-12Per Hedbor  if(c<128){if(c >= 'a' && c <= 'z' ) C=c-0x20;}else {\
94d9921999-03-20Henrik Grubbström (Grubba)  struct case_info *ci = find_ci(c); \ if (ci) { \ switch(ci->mode) { \
164d671999-03-20Henrik Grubbström (Grubba)  case CIM_NONE: case CIM_UPPERDELTA: break; \ case CIM_LOWERDELTA: C = c - ci->data; break; \ case CIM_CASEBIT: C = c & ~ci->data; break; \
94d9921999-03-20Henrik Grubbström (Grubba)  case CIM_CASEBITOFF: C = ((c - ci->data)& ~ci->data) + ci->data; break; \
5aad932002-08-15Marcus Comstedt  default: Pike_fatal("upper_case(): Unknown case_info mode: %d\n", ci->mode); \
94d9921999-03-20Henrik Grubbström (Grubba)  } \
bd662f2004-04-12Per Hedbor  }} \
94d9921999-03-20Henrik Grubbström (Grubba)  } while(0)
480bf02000-07-27Andreas Lange #define DO_UPPER_CASE_SHIFT0(C) do {\
9776dd2001-06-21Henrik Grubbström (Grubba)  INT32 c = C; \
bd662f2004-04-12Per Hedbor  if(c<128){if(c >= 'a' && c <= 'z' ) C=c-0x20;}else {\
480bf02000-07-27Andreas Lange  struct case_info *ci = find_ci_shift0(c); \ if (ci) { \ switch(ci->mode) { \ case CIM_NONE: case CIM_UPPERDELTA: break; \ case CIM_LOWERDELTA: C = c - ci->data; break; \ case CIM_CASEBIT: C = c & ~ci->data; break; \ case CIM_CASEBITOFF: C = ((c - ci->data)& ~ci->data) + ci->data; break; \
5aad932002-08-15Marcus Comstedt  default: Pike_fatal("lower_case(): Unknown case_info mode: %d\n", ci->mode); \
480bf02000-07-27Andreas Lange  } \
bd662f2004-04-12Per Hedbor  }} \
480bf02000-07-27Andreas Lange  } while(0)
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl string lower_case(string s)
6f18562003-09-05Henrik Grubbström (Grubba)  *! @decl int lower_case(int c)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
6f18562003-09-05Henrik Grubbström (Grubba)  *! Convert a string or character to lower case.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! @returns *! Returns a copy of the string @[s] with all upper case characters
6f18562003-09-05Henrik Grubbström (Grubba)  *! converted to lower case, or the character @[c] converted to lower *! case. *! *! @note *! Assumes the string or character to be coded according to
09bc452003-09-05Johan Sundström  *! ISO-10646 (aka Unicode). If they are not, @[Locale.Charset.decoder] *! can do the initial conversion for you.
6f18562003-09-05Henrik Grubbström (Grubba)  *! *! @note *! Prior to Pike 7.5 this function only accepted strings.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
09bc452003-09-05Johan Sundström  *! @[upper_case()], @[Locale.Charset.decoder]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_lower_case(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
93b7202000-08-14Henrik Grubbström (Grubba)  ptrdiff_t i;
cabe031999-03-19Henrik Grubbström (Grubba)  struct pike_string *orig;
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *ret;
6f18562003-09-05Henrik Grubbström (Grubba)  check_all_args("lower_case", args, BIT_STRING|BIT_INT, 0); if (Pike_sp[-args].type == T_INT) { /* NOTE: Performs the case change in place. */ DO_LOWER_CASE(Pike_sp[-args].u.integer); pop_n_elems(args-1); return; }
c5ab042004-05-13Martin Nilsson  orig = Pike_sp[-args].u.string;
94d9921999-03-20Henrik Grubbström (Grubba)  ret = begin_wide_shared_string(orig->len, orig->size_shift); MEMCPY(ret->str, orig->str, orig->len << orig->size_shift); i = orig->len;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
94d9921999-03-20Henrik Grubbström (Grubba)  if (!orig->size_shift) { p_wchar0 *str = STR0(ret); while(i--) {
480bf02000-07-27Andreas Lange  DO_LOWER_CASE_SHIFT0(str[i]);
94d9921999-03-20Henrik Grubbström (Grubba)  } } else if (orig->size_shift == 1) { p_wchar1 *str = STR1(ret); while(i--) { DO_LOWER_CASE(str[i]); } } else if (orig->size_shift == 2) { p_wchar2 *str = STR2(ret); while(i--) { DO_LOWER_CASE(str[i]); } } else {
5aad932002-08-15Marcus Comstedt  Pike_fatal("lower_case(): Bad string shift:%d\n", orig->size_shift);
94d9921999-03-20Henrik Grubbström (Grubba)  }
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_string(end_shared_string(ret)); }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl string upper_case(string s)
6f18562003-09-05Henrik Grubbström (Grubba)  *! @decl int upper_case(int c)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
6f18562003-09-05Henrik Grubbström (Grubba)  *! Convert a string or character to upper case.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! @returns *! Returns a copy of the string @[s] with all lower case characters
6f18562003-09-05Henrik Grubbström (Grubba)  *! converted to upper case, or the character @[c] converted to upper *! case. *! *! @note *! Assumes the string or character to be coded according to
09bc452003-09-05Johan Sundström  *! ISO-10646 (aka Unicode). If they are not, @[Locale.Charset.decoder] *! can do the initial conversion for you.
6f18562003-09-05Henrik Grubbström (Grubba)  *! *! @note *! Prior to Pike 7.5 this function only accepted strings.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
09bc452003-09-05Johan Sundström  *! @[lower_case()], @[Locale.Charset.decoder]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_upper_case(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
93b7202000-08-14Henrik Grubbström (Grubba)  ptrdiff_t i;
cabe031999-03-19Henrik Grubbström (Grubba)  struct pike_string *orig;
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *ret;
6f18562003-09-05Henrik Grubbström (Grubba)  check_all_args("upper_case", args, BIT_STRING|BIT_INT, 0); if (Pike_sp[-args].type == T_INT) { /* NOTE: Performs the case change in place. */ DO_UPPER_CASE(Pike_sp[-args].u.integer); pop_n_elems(args-1); return; }
c5ab042004-05-13Martin Nilsson  orig = Pike_sp[-args].u.string;
5e3f721999-03-20Per Hedbor  ret=begin_wide_shared_string(orig->len,orig->size_shift);
164d671999-03-20Henrik Grubbström (Grubba)  MEMCPY(ret->str, orig->str, orig->len << orig->size_shift);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
94d9921999-03-20Henrik Grubbström (Grubba)  i = orig->len; if (!orig->size_shift) { p_wchar0 *str = STR0(ret); while(i--) {
0cb4152000-07-19Andreas Lange  if(str[i]!=0xff && str[i]!=0xb5) {
480bf02000-07-27Andreas Lange  DO_UPPER_CASE_SHIFT0(str[i]);
94d9921999-03-20Henrik Grubbström (Grubba)  } else {
c5ab042004-05-13Martin Nilsson  /* Ok, so our shiftsize 0 string contains 0xff or 0xb5 which prompts for a shiftsize 1 string. */ int j = orig->len; struct pike_string *wret = begin_wide_shared_string(j, 1); p_wchar1 *wstr = STR1(wret); /* Copy what we have done */ while(--j>i) wstr[j] = str[j]; /* upper case the rest */ i++; while(i--) switch( str[i] ) { case 0xff: wstr[i] = 0x178; break; case 0xb5: wstr[i] = 0x39c; break; default: DO_UPPER_CASE_SHIFT0(str[i]); wstr[i] = str[i]; break; } /* Discard the too narrow string and use the new one instead. */ do_really_free_pike_string(ret); ret = wret; break;
94d9921999-03-20Henrik Grubbström (Grubba)  } } } else if (orig->size_shift == 1) { p_wchar1 *str = STR1(ret); while(i--) { DO_UPPER_CASE(str[i]); } } else if (orig->size_shift == 2) { p_wchar2 *str = STR2(ret); while(i--) { DO_UPPER_CASE(str[i]); } } else {
5aad932002-08-15Marcus Comstedt  Pike_fatal("lower_case(): Bad string shift:%d\n", orig->size_shift);
94d9921999-03-20Henrik Grubbström (Grubba)  }
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_string(end_shared_string(ret)); }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl string random_string(int len) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Returns a string of random characters 0-255 with the length @[len].
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_random_string(INT32 args)
283ec72000-04-15Fredrik Hübinette (Hubbe) { struct pike_string *ret;
65a5492000-08-10Per Hedbor  INT_TYPE len, e;
2575242004-05-14Martin Nilsson  get_all_args("random_string",args,"%+",&len);
283ec72000-04-15Fredrik Hübinette (Hubbe)  ret = begin_shared_string(len);
1f88bf2001-09-24Henrik Grubbström (Grubba)  for(e=0;e<len;e++) ret->str[e] = DO_NOT_WARN((char)my_rand());
283ec72000-04-15Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_string(end_shared_string(ret)); }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl void random_seed(int seed) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function sets the initial value for the random generator.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[random()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_random_seed(INT32 args)
cb22561995-10-11Fredrik Hübinette (Hubbe) {
8aefbc1999-03-19Fredrik Hübinette (Hubbe)  INT_TYPE i;
e37a3e1999-10-09Fredrik Hübinette (Hubbe) #ifdef AUTO_BIGNUM check_all_args("random_seed",args,BIT_INT | BIT_OBJECT, 0);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[-args].type == T_INT)
ca94762000-01-09Fredrik Hübinette (Hubbe)  {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  i=Pike_sp[-args].u.integer;
ca94762000-01-09Fredrik Hübinette (Hubbe)  }else{
edf4d02000-07-06Fredrik Hübinette (Hubbe)  i=hash_svalue(Pike_sp-args);
ca94762000-01-09Fredrik Hübinette (Hubbe)  }
e37a3e1999-10-09Fredrik Hübinette (Hubbe) #else
8aefbc1999-03-19Fredrik Hübinette (Hubbe)  get_all_args("random_seed",args,"%i",&i);
e37a3e1999-10-09Fredrik Hübinette (Hubbe) #endif
8aefbc1999-03-19Fredrik Hübinette (Hubbe)  my_srand(i);
f6f02d1995-10-16Fredrik Hübinette (Hubbe)  pop_n_elems(args);
cb22561995-10-11Fredrik Hübinette (Hubbe) }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl int query_num_arg() *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Returns the number of arguments given when the previous function was *! called.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This is useful for functions that take a variable number of arguments.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[call_function()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
5267b71995-08-09Fredrik Hübinette (Hubbe) void f_query_num_arg(INT32 args) { pop_n_elems(args);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  push_int(Pike_fp ? Pike_fp->args : 0);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
9cf6c82001-03-11Henrik Grubbström (Grubba) /*! @decl int search(string haystack, string|int needle, int|void start)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! @decl int search(array haystack, mixed needle, int|void start) *! @decl mixed search(mapping haystack, mixed needle, mixed|void start)
b5b59a2003-09-04Henrik Grubbström (Grubba)  *! @decl mixed search(object haystack, mixed needle, mixed|void start)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Search for @[needle] in @[haystack]. Return the position of @[needle] in
cbe8c92003-04-07Martin Nilsson  *! @[haystack] or @expr{-1@} if not found.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! If the optional argument @[start] is present search is started at *! this position.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
b5b59a2003-09-04Henrik Grubbström (Grubba)  *! @mixed haystack *! @type string *! When @[haystack] is a string @[needle] must be a string or an int, *! and the first occurrence of the string or int is returned. *! *! @type array *! When @[haystack] is an array, @[needle] is compared only to *! one value at a time in @[haystack]. *! *! @type mapping *! When @[haystack] is a mapping, @[search()] tries to find the index *! connected to the data @[needle]. That is, it tries to lookup the *! mapping backwards. If @[needle] isn't present in the mapping, zero *! is returned, and zero_type() will return 1 for this zero. *! *! @type object *! When @[haystack] is an object implementing @[lfun::_search()], *! the result of calling @[lfun::_search()] with @[needle] will *! be returned. *! *! If @[haystack] is an object that doesn't implement @[lfun::_search()] *! it is assumed to be an @[Iterator], and implement *! @[Iterator()->index()], @[Iterator()->value()], and *! @[Iterator()->next()]. @[search()] will then start comparing *! elements with @[`==()] until a match with @[needle] is found. *! If @[needle] is found @[haystack] will be advanced to the element, *! and the iterator index will be returned. If @[needle] is not *! found, @[haystack] will be advanced to the end (and will thus *! evaluate to false), and a zero with zero_type 1 will be returned. *! @endmixed
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
b5b59a2003-09-04Henrik Grubbström (Grubba)  *! @note *! If @[start] is supplied to an iterator object without an *! @[lfun::_search()], @[haystack] will need to implement *! @[Iterator()->set_index()].
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[indices()], @[values()], @[zero_type()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_search(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
93b7202000-08-14Henrik Grubbström (Grubba)  ptrdiff_t start;
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(args < 2)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_TOO_FEW_ARGS_ERROR("search", 2);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  switch(Pike_sp[-args].type)
5267b71995-08-09Fredrik Hübinette (Hubbe)  { case T_STRING: {
9cf6c82001-03-11Henrik Grubbström (Grubba)  struct pike_string *haystack = Pike_sp[-args].u.string;
5267b71995-08-09Fredrik Hübinette (Hubbe)  start=0; if(args > 2) {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[2-args].type!=T_INT)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("search", 3, "int");
5267b71995-08-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  start=Pike_sp[2-args].u.integer;
d0d01b1999-03-20Henrik Grubbström (Grubba)  if(start<0) {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  bad_arg_error("search", Pike_sp-args, args, 3, "int(0..)", Pike_sp+2-args,
d0d01b1999-03-20Henrik Grubbström (Grubba)  "Start must be greater or equal to zero.\n"); }
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
9cf6c82001-03-11Henrik Grubbström (Grubba)  if(haystack->len < start) bad_arg_error("search", Pike_sp-args, args, 3, "int(0..)", Pike_sp-args,
d0d01b1999-03-20Henrik Grubbström (Grubba)  "Start must not be greater than the " "length of the string.\n");
84f4f91998-02-27Fredrik Hübinette (Hubbe) 
9cf6c82001-03-11Henrik Grubbström (Grubba)  if(Pike_sp[1-args].type == T_STRING) {
e38ce92001-10-30Henrik Grubbström (Grubba)  /* Handle searching for the empty string. */ if (Pike_sp[1-args].u.string->len) { start = string_search(haystack, Pike_sp[1-args].u.string, start); }
9cf6c82001-03-11Henrik Grubbström (Grubba)  } else if (Pike_sp[1-args].type == T_INT) { INT_TYPE val = Pike_sp[1-args].u.integer; switch(Pike_sp[-args].u.string->size_shift) { case 0: { p_wchar0 *str = STR0(haystack); if (val >= 256) { start = -1; break; } while (start < haystack->len) { if (str[start] == val) break; start++; } } break; case 1: { p_wchar1 *str = STR1(haystack); if (val >= 65536) { start = -1; break; } while (start < haystack->len) { if (str[start] == val) break; start++; } } break; case 2: { p_wchar2 *str = STR2(haystack); while (start < haystack->len) { if (str[start] == (p_wchar2)val) break; start++; } } break; default:
5aad932002-08-15Marcus Comstedt  Pike_fatal("search(): Unsupported string shift: %d!\n",
9cf6c82001-03-11Henrik Grubbström (Grubba)  haystack->size_shift); break; } if (start >= haystack->len) { start = -1; } } else { SIMPLE_BAD_ARG_ERROR("search", 2, "string | int"); }
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args);
93b7202000-08-14Henrik Grubbström (Grubba)  push_int64(start);
5267b71995-08-09Fredrik Hübinette (Hubbe)  break; } case T_ARRAY: start=0; if(args > 2) {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[2-args].type!=T_INT)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("search", 3, "int");
5267b71995-08-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  start=Pike_sp[2-args].u.integer;
c2998a1999-11-08Henrik Grubbström (Grubba)  if(start<0) {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  bad_arg_error("search", Pike_sp-args, args, 3, "int(0..)", Pike_sp+2-args,
c2998a1999-11-08Henrik Grubbström (Grubba)  "Start must be greater or equal to zero.\n"); }
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
edf4d02000-07-06Fredrik Hübinette (Hubbe)  start=array_search(Pike_sp[-args].u.array,Pike_sp+1-args,start);
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args);
93b7202000-08-14Henrik Grubbström (Grubba)  push_int64(start);
5267b71995-08-09Fredrik Hübinette (Hubbe)  break; case T_MAPPING:
c2998a1999-11-08Henrik Grubbström (Grubba)  if(args > 2) {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  mapping_search_no_free(Pike_sp,Pike_sp[-args].u.mapping,Pike_sp+1-args,Pike_sp+2-args);
c2998a1999-11-08Henrik Grubbström (Grubba)  } else {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  mapping_search_no_free(Pike_sp,Pike_sp[-args].u.mapping,Pike_sp+1-args,0);
c2998a1999-11-08Henrik Grubbström (Grubba)  }
edf4d02000-07-06Fredrik Hübinette (Hubbe)  free_svalue(Pike_sp-args); Pike_sp[-args]=*Pike_sp; dmalloc_touch_svalue(Pike_sp);
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args-1); return;
b5b59a2003-09-04Henrik Grubbström (Grubba)  case T_OBJECT:
e0024c2003-09-04Henrik Grubbström (Grubba)  if (Pike_sp[-args].u.object->prog) {
b5b59a2003-09-04Henrik Grubbström (Grubba)  struct object *o = Pike_sp[-args].u.object;
e0024c2003-09-04Henrik Grubbström (Grubba)  struct program *p = o->prog;
b5b59a2003-09-04Henrik Grubbström (Grubba)  /* NOTE: Fake lfun! */
e0024c2003-09-04Henrik Grubbström (Grubba)  int id = low_find_lfun(p, LFUN__SEARCH);
b5b59a2003-09-04Henrik Grubbström (Grubba)  int next, ind; /* First try lfun::_search(). */ if (id >= 0) {
3c8f3d2003-09-05Henrik Grubbström (Grubba)  apply_low(o, id, args-1);
b5b59a2003-09-04Henrik Grubbström (Grubba)  stack_pop_n_elems_keep_top(1); return; } /* Check if we have an iterator. */
e0024c2003-09-04Henrik Grubbström (Grubba)  if (((id = find_identifier("value", p)) >= 0) && ((next = find_identifier("next", p)) >= 0) && ((ind = find_identifier("index", p)) >= 0)) {
b5b59a2003-09-04Henrik Grubbström (Grubba)  /* We have an iterator. */ /* Set the start position if needed. */ if (args > 2) { apply(o, "set_index", args-2); pop_stack(); } /* At this point we have two values on the stack. */ while(1) {
3c8f3d2003-09-05Henrik Grubbström (Grubba)  apply_low(o, id, 0);
b5b59a2003-09-04Henrik Grubbström (Grubba)  if (is_eq(Pike_sp-2, Pike_sp-1)) { /* Found. */
3c8f3d2003-09-05Henrik Grubbström (Grubba)  apply_low(o, ind, 0);
b5b59a2003-09-04Henrik Grubbström (Grubba)  stack_pop_n_elems_keep_top(3); return; }
3c8f3d2003-09-05Henrik Grubbström (Grubba)  apply_low(o, next, 0);
b5b59a2003-09-04Henrik Grubbström (Grubba)  if (UNSAFE_IS_ZERO(Pike_sp-1)) { /* Not found. */ pop_n_elems(4); /* FIXME: Should probably indicate not found in some other way. * On the other hand, the iterator should be false now. */ push_undefined(); return; } pop_n_elems(2); } } } /* FALL_THROUGH */
5267b71995-08-09Fredrik Hübinette (Hubbe)  default:
b5b59a2003-09-04Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("search", 1, "string|array|mapping|object");
5267b71995-08-09Fredrik Hübinette (Hubbe)  } }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl int has_prefix(string s, string prefix) *!
cbe8c92003-04-07Martin Nilsson  *! Returns @expr{1@} if the string @[s] starts with @[prefix], *! returns @expr{0@} (zero) otherwise.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_has_prefix(INT32 args)
a4f17f2000-04-12Henrik Grubbström (Grubba) { struct pike_string *a, *b;
7d1e032004-05-18Martin Nilsson  if(args<2) SIMPLE_TOO_FEW_ARGS_ERROR("has_prefix", 2); if(Pike_sp[-args].type!=T_STRING) SIMPLE_ARG_TYPE_ERROR("has_prefix", 1, "string"); if(Pike_sp[1-args].type!=T_STRING) SIMPLE_ARG_TYPE_ERROR("has_prefix", 2, "string"); a = Pike_sp[-args].u.string; b = Pike_sp[1-args].u.string;
a4f17f2000-04-12Henrik Grubbström (Grubba)  /* First handle some common special cases. */ if ((b->len > a->len) || (b->size_shift > a->size_shift)) { pop_n_elems(args); push_int(0); return; } /* Trivial cases. */ if ((a == b)||(!b->len)) { pop_n_elems(args); push_int(1); return; } if (a->size_shift == b->size_shift) { int res = !MEMCMP(a->str, b->str, b->len << b->size_shift); pop_n_elems(args); push_int(res); return; } /* At this point a->size_shift > b->size_shift */ #define TWO_SHIFTS(S1, S2) ((S1)|((S2)<<2)) switch(TWO_SHIFTS(a->size_shift, b->size_shift)) { #define CASE_SHIFT(S1, S2) \ case TWO_SHIFTS(S1, S2): \ { \ PIKE_CONCAT(p_wchar,S1) *s1 = PIKE_CONCAT(STR,S1)(a); \ PIKE_CONCAT(p_wchar,S2) *s2 = PIKE_CONCAT(STR,S2)(b); \
93b7202000-08-14Henrik Grubbström (Grubba)  ptrdiff_t len = b->len; \
a4f17f2000-04-12Henrik Grubbström (Grubba)  while(len-- && (s1[len] == s2[len])) \ ; \ pop_n_elems(args); \ push_int(len == -1); \ return; \ } \ break CASE_SHIFT(1,0); CASE_SHIFT(2,0); CASE_SHIFT(2,1); default:
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("has_prefix(): Unexpected string shift combination: a:%d, b:%d!\n",
a4f17f2000-04-12Henrik Grubbström (Grubba)  a->size_shift, b->size_shift); break; } #undef CASE_SHIFT #undef TWO_SHIFTS }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl int has_suffix(string s, string suffix) *!
cbe8c92003-04-07Martin Nilsson  *! Returns @expr{1@} if the string @[s] ends with @[suffix], *! returns @expr{0@} (zero) otherwise.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
54277b2000-12-18Henrik Grubbström (Grubba) PMOD_EXPORT void f_has_suffix(INT32 args) { struct pike_string *a, *b;
7d1e032004-05-18Martin Nilsson  if(args<2) SIMPLE_TOO_FEW_ARGS_ERROR("has_suffix", 2); if(Pike_sp[-args].type!=T_STRING) SIMPLE_ARG_TYPE_ERROR("has_suffix", 1, "string"); if(Pike_sp[1-args].type!=T_STRING) SIMPLE_ARG_TYPE_ERROR("has_suffix", 2, "string"); a = Pike_sp[-args].u.string; b = Pike_sp[1-args].u.string;
54277b2000-12-18Henrik Grubbström (Grubba)  /* First handle some common special cases. */ if ((b->len > a->len) || (b->size_shift > a->size_shift)) { pop_n_elems(args); push_int(0); return; } /* Trivial cases. */ if ((a == b)||(!b->len)) { pop_n_elems(args); push_int(1); return; } if (a->size_shift == b->size_shift) {
ce1a582000-12-18Henrik Grubbström (Grubba)  int res = !MEMCMP(a->str + ((a->len - b->len)<<b->size_shift), b->str,
54277b2000-12-18Henrik Grubbström (Grubba)  b->len << b->size_shift); pop_n_elems(args); push_int(res); return; } /* At this point a->size_shift > b->size_shift */ #define TWO_SHIFTS(S1, S2) ((S1)|((S2)<<2)) switch(TWO_SHIFTS(a->size_shift, b->size_shift)) { #define CASE_SHIFT(S1, S2) \ case TWO_SHIFTS(S1, S2): \ { \ PIKE_CONCAT(p_wchar,S1) *s1 = PIKE_CONCAT(STR,S1)(a) + a->len - b->len; \ PIKE_CONCAT(p_wchar,S2) *s2 = PIKE_CONCAT(STR,S2)(b); \ ptrdiff_t len = b->len; \ while(len-- && (s1[len] == s2[len])) \ ; \ pop_n_elems(args); \ push_int(len == -1); \ return; \ } \ break CASE_SHIFT(1,0); CASE_SHIFT(2,0); CASE_SHIFT(2,1); default: Pike_error("has_prefix(): Unexpected string shift combination: a:%d, b:%d!\n", a->size_shift, b->size_shift); break; } #undef CASE_SHIFT #undef TWO_SHIFTS }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl int has_index(string haystack, int index) *! @decl int has_index(array haystack, int index)
01587a2003-06-03Martin Stjernholm  *! @decl int has_index(mapping|multiset|object|program haystack, mixed index)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Search for @[index] in @[haystack].
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! @returns
cbe8c92003-04-07Martin Nilsson  *! Returns @expr{1@} if @[index] is in the index domain of @[haystack], *! or @expr{0@} (zero) if not found.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function is equivalent to (but sometimes faster than):
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
f79bd82003-04-01Martin Nilsson  *! @code *! search(indices(haystack), index) != -1 *! @endcode
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @note
554e222001-05-06Henrik Grubbström (Grubba)  *! A negative index in strings and arrays as recognized by the
cbe8c92003-04-07Martin Nilsson  *! index operators @expr{`[]()@} and @expr{`[]=()@} is not considered
554e222001-05-06Henrik Grubbström (Grubba)  *! a proper index by @[has_index()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[has_value()], @[indices()], @[search()], @[values()], @[zero_type()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_has_index(INT32 args)
538a892000-01-21Fredrik Noring { int t = 0;
e74e2c2003-01-05Martin Nilsson  if(args < 2) SIMPLE_TOO_FEW_ARGS_ERROR("has_index", 2); if(args > 2) pop_n_elems(args-2);
538a892000-01-21Fredrik Noring 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  switch(Pike_sp[-2].type)
538a892000-01-21Fredrik Noring  { case T_STRING:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[-1].type == T_INT) t = (0 <= Pike_sp[-1].u.integer && Pike_sp[-1].u.integer < Pike_sp[-2].u.string->len);
538a892000-01-21Fredrik Noring  pop_n_elems(args); push_int(t); break; case T_ARRAY:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[-1].type == T_INT) t = (0 <= Pike_sp[-1].u.integer && Pike_sp[-1].u.integer < Pike_sp[-2].u.array->size);
538a892000-01-21Fredrik Noring  pop_n_elems(args); push_int(t); break; case T_MULTISET: case T_MAPPING: f_index(2); f_zero_type(1);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[-1].type == T_INT) Pike_sp[-1].u.integer = !Pike_sp[-1].u.integer;
538a892000-01-21Fredrik Noring  else PIKE_ERROR("has_index",
edf4d02000-07-06Fredrik Hübinette (Hubbe)  "Function `zero_type' gave incorrect result.\n", Pike_sp, args);
538a892000-01-21Fredrik Noring  break; case T_OBJECT:
01587a2003-06-03Martin Stjernholm  case T_PROGRAM:
7b58042000-01-24Fredrik Noring  /* FIXME: If the object behaves like an array, it will throw an
a4a1722000-12-05Per Hedbor  error for non-valid indices. Therefore it's not a good idea
7b58042000-01-24Fredrik Noring  to use the index operator. Maybe we should use object->_has_index(index) provided that the object implements it.
538a892000-01-21Fredrik Noring  /Noring */ stack_swap(); f_indices(1); stack_swap(); f_search(2);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[-1].type == T_INT) Pike_sp[-1].u.integer = (Pike_sp[-1].u.integer != -1);
538a892000-01-21Fredrik Noring  else PIKE_ERROR("has_index",
edf4d02000-07-06Fredrik Hübinette (Hubbe)  "Function `search' gave incorrect result.\n", Pike_sp, args);
01587a2003-06-03Martin Stjernholm  break; default: SIMPLE_ARG_TYPE_ERROR ("has_index", 1, "string|array|mapping|multiset|object|program");
538a892000-01-21Fredrik Noring  } }
9cf6c82001-03-11Henrik Grubbström (Grubba) /*! @decl int has_value(string haystack, string value) *! @decl int has_value(string haystack, int value)
01587a2003-06-03Martin Stjernholm  *! @decl int has_value(array|mapping|object|program haystack, mixed value)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Search for @[value] in @[haystack].
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! @returns
cbe8c92003-04-07Martin Nilsson  *! Returns @expr{1@} if @[value] is in the value domain of @[haystack], *! or @expr{0@} (zero) if not found.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function is in all cases except when both arguments are strings *! equivalent to (but sometimes faster than):
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
f79bd82003-04-01Martin Nilsson  *! @code *! search(values(@[haystack]), @[value]) != -1 *! @endcode
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! If both arguments are strings, @[has_value()] is equivalent to:
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
f79bd82003-04-01Martin Nilsson  *! @code *! search(@[haystack], @[value]) != -1 *! @endcode
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[has_index()], @[indices()], @[search()], @[values()], @[zero_type()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_has_value(INT32 args)
538a892000-01-21Fredrik Noring {
e74e2c2003-01-05Martin Nilsson  if(args < 2) SIMPLE_TOO_FEW_ARGS_ERROR("has_value", 2); if(args > 2) pop_n_elems(args-2);
538a892000-01-21Fredrik Noring 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  switch(Pike_sp[-2].type)
538a892000-01-21Fredrik Noring  { case T_MAPPING: f_search(2); f_zero_type(1);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[-1].type == T_INT) Pike_sp[-1].u.integer = !Pike_sp[-1].u.integer;
538a892000-01-21Fredrik Noring  else PIKE_ERROR("has_value",
edf4d02000-07-06Fredrik Hübinette (Hubbe)  "Function `zero_type' gave incorrect result.\n", Pike_sp, args);
538a892000-01-21Fredrik Noring  break;
01587a2003-06-03Martin Stjernholm  case T_PROGRAM:
538a892000-01-21Fredrik Noring  case T_OBJECT: /* FIXME: It's very sad that we always have to do linear search with `values' in case of objects. The problem is that we cannot use `search' directly since it's undefined weather it returns -1 (array) or 0 (mapping) during e.g. some data type emulation.
7b58042000-01-24Fredrik Noring  Maybe we should use object->_has_value(value) provided that the object implements it.
538a892000-01-21Fredrik Noring  /Noring */
9cf6c82001-03-11Henrik Grubbström (Grubba)  /* FALL_THROUGH */
01587a2003-06-03Martin Stjernholm  case T_MULTISET: /* FIXME: This behavior for multisets isn't clean. It should be * compat only. */
538a892000-01-21Fredrik Noring  stack_swap(); f_values(1); stack_swap();
01587a2003-06-03Martin Stjernholm  /* FALL_THROUGH */
aa14882000-01-24Martin Stjernholm  case T_STRING: /* Strings are odd. /Noring */
538a892000-01-21Fredrik Noring  case T_ARRAY: f_search(2);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[-1].type == T_INT) Pike_sp[-1].u.integer = (Pike_sp[-1].u.integer != -1);
538a892000-01-21Fredrik Noring  else
edf4d02000-07-06Fredrik Hübinette (Hubbe)  PIKE_ERROR("has_value", "Search gave incorrect result.\n", Pike_sp, args);
01587a2003-06-03Martin Stjernholm  break; default: SIMPLE_ARG_TYPE_ERROR ("has_value", 1, "string|array|mapping|object|program");
538a892000-01-21Fredrik Noring  } }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl void add_constant(string name, mixed value) *! @decl void add_constant(string name) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Add a new predefined constant.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function is often used to add builtin functions. *! All programs compiled after the @[add_constant()] function has been *! called can access @[value] by the name @[name].
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! If there is a constant called @[name] already, it will be replaced by *! by the new definition. This will not affect already compiled programs.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Calling @[add_constant()] without a value will remove that name from *! the list of constants. As with replacing, this will not affect already *! compiled programs.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[all_constants()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_add_constant(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
8111162003-09-07Martin Nilsson  ASSERT_SECURITY_ROOT("add_constant");
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(args<1)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_TOO_FEW_ARGS_ERROR("add_constant", 1);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[-args].type!=T_STRING)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("add_constant", 1, "string");
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(args>1) {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  dmalloc_touch_svalue(Pike_sp-args+1); low_add_efun(Pike_sp[-args].u.string, Pike_sp-args+1);
5267b71995-08-09Fredrik Hübinette (Hubbe)  }else{
edf4d02000-07-06Fredrik Hübinette (Hubbe)  low_add_efun(Pike_sp[-args].u.string, 0);
5267b71995-08-09Fredrik Hübinette (Hubbe)  } pop_n_elems(args); }
f7fb1a2004-05-01Martin Stjernholm /*! @decl string combine_path(string path, string ... paths) *! @decl string combine_path_unix(string path, string ... paths) *! @decl string combine_path_nt(string path, string ... paths) *! @decl string combine_path_amigaos(string path, string ... paths) *! *! Concatenate a number of paths to a straightforward path without *! any @expr{"//"@}, @expr{"/.."@} or @expr{"/."@}. If any path *! argument is absolute then the result is absolute and the *! preceding arguments are ignored. If the result is relative then *! it might have leading @expr{".."@} components. If the last *! nonempty argument ends with a directory separator then the *! result ends with that too. If all components in a relative path *! disappear due to subsequent @expr{".."@} components then the *! result is @expr{"."@}.
97e8162004-05-01Martin Stjernholm  *! *! @[combine_path_unix()] concatenates in UNIX style, which also is *! appropriate for e.g. URL:s ("/" separates path components and *! absolute paths start with "/"). @[combine_path_nt()] *! concatenates according to NT filesystem conventions ("/" and "\" *! separates path components and there might be a drive letter in *! front of absolute paths). @[combine_path_amigaos()] concatenates *! according to AmigaOS filesystem conventions. *! *! @[combine_path()] is equivalent to @[combine_path_unix()] on UNIX-like
81ffaa2003-12-18Marcus Comstedt  *! operating systems, and equivalent to @[combine_path_nt()] on NT-like *! operating systems, and equivalent to @[combine_path_amigaos()] on *! AmigaOS-like operating systems.
9849a72001-06-08Henrik Grubbström (Grubba)  *!
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[getcwd()], @[Stdio.append_path()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
05459a1998-04-09Fredrik Hübinette (Hubbe) 
8e06782001-06-07Fredrik Hübinette (Hubbe) #define NT_COMBINE_PATH #include "combine_path.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) 
8e06782001-06-07Fredrik Hübinette (Hubbe) #define UNIX_COMBINE_PATH #include "combine_path.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) 
81ffaa2003-12-18Marcus Comstedt #define AMIGAOS_COMBINE_PATH #include "combine_path.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) 
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl int zero_type(mixed a) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Return the type of zero.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! There are many types of zeros out there, or at least there are two. *! One is returned by normal functions, and one returned by mapping *! lookups and @[find_call_out()] when what you looked for wasn't there. *! The only way to separate these two kinds of zeros is @[zero_type()].
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! @returns *! When doing a @[find_call_out()] or mapping lookup, @[zero_type()] on
cbe8c92003-04-07Martin Nilsson  *! this value will return @expr{1@} if there was no such thing present in
554e222001-05-06Henrik Grubbström (Grubba)  *! the mapping, or if no such @tt{call_out@} could be found.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! If the argument to @[zero_type()] is a destructed object or a function
cbe8c92003-04-07Martin Nilsson  *! in a destructed object, @expr{2@} will be returned.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
cbe8c92003-04-07Martin Nilsson  *! In all other cases @[zero_type()] will return @expr{0@} (zero).
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
8459bf2001-07-27Martin Nilsson  *! @[find_call_out()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_zero_type(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) { if(args < 1)
8aefbc1999-03-19Fredrik Hübinette (Hubbe)  SIMPLE_TOO_FEW_ARGS_ERROR("zero_type",1);
eaa4da2001-10-04Fredrik Hübinette (Hubbe)  if((Pike_sp[-args].type==T_OBJECT || Pike_sp[-args].type==T_FUNCTION) && !Pike_sp[-args].u.object->prog)
3f6d8f1996-11-26Fredrik Hübinette (Hubbe)  { pop_n_elems(args);
eaa4da2001-10-04Fredrik Hübinette (Hubbe)  push_int(NUMBER_DESTRUCTED);
8e9fdf1996-12-04Fredrik Hübinette (Hubbe)  }
eaa4da2001-10-04Fredrik Hübinette (Hubbe)  else if(Pike_sp[-args].type != T_INT)
8e9fdf1996-12-04Fredrik Hübinette (Hubbe)  { pop_n_elems(args);
eaa4da2001-10-04Fredrik Hübinette (Hubbe)  push_int(0);
8e9fdf1996-12-04Fredrik Hübinette (Hubbe)  }
eaa4da2001-10-04Fredrik Hübinette (Hubbe)  else
8e9fdf1996-12-04Fredrik Hübinette (Hubbe)  {
3f6d8f1996-11-26Fredrik Hübinette (Hubbe)  pop_n_elems(args-1);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  Pike_sp[-1].u.integer=Pike_sp[-1].subtype; Pike_sp[-1].subtype=NUMBER_NUMBER;
3f6d8f1996-11-26Fredrik Hübinette (Hubbe)  }
5267b71995-08-09Fredrik Hübinette (Hubbe) }
0811472001-07-02Fredrik Hübinette (Hubbe) static int generate_zero_type(node *n) { if(count_args(CDR(n)) != 1) return 0; if(do_docode(CDR(n),DO_NOT_COPY) != 1)
5aad932002-08-15Marcus Comstedt  Pike_fatal("Count args was wrong in generate_zero_type().\n");
0811472001-07-02Fredrik Hübinette (Hubbe)  emit0(F_ZERO_TYPE); return 1; }
4643ea1998-10-10Henrik Grubbström (Grubba) /* * Some wide-strings related functions */
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl string string_to_unicode(string s) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Converts a string into an UTF16 compliant byte-stream.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @note
554e222001-05-06Henrik Grubbström (Grubba)  *! Throws an error if characters not legal in an UTF16 stream are *! encountered. Valid characters are in the range 0x00000 - 0x10ffff, *! except for characters 0xfffe and 0xffff.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Characters in range 0x010000 - 0x10ffff are encoded using surrogates.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
a056042001-10-28Martin Nilsson  *! @[Locale.Charset.decoder()], @[string_to_utf8()], @[unicode_to_string()],
554e222001-05-06Henrik Grubbström (Grubba)  *! @[utf8_to_string()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_string_to_unicode(INT32 args)
4643ea1998-10-10Henrik Grubbström (Grubba) { struct pike_string *in; struct pike_string *out = NULL;
93b7202000-08-14Henrik Grubbström (Grubba)  ptrdiff_t len; ptrdiff_t i;
4643ea1998-10-10Henrik Grubbström (Grubba) 
1d8bb01998-10-10Henrik Grubbström (Grubba)  get_all_args("string_to_unicode", args, "%W", &in);
4643ea1998-10-10Henrik Grubbström (Grubba)  switch(in->size_shift) { case 0: /* Just 8bit characters */ len = in->len * 2; out = begin_shared_string(len);
89a70c2000-08-28Henrik Grubbström (Grubba)  if (len) { MEMSET(out->str, 0, len); /* Clear the upper (and lower) byte */ #ifdef PIKE_DEBUG if (d_flag) { for(i = len; i--;) { if (out->str[i]) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("MEMSET didn't clear byte %ld of %ld\n",
d1cac52000-09-07Henrik Grubbström (Grubba)  PTRDIFF_T_TO_LONG(i+1), PTRDIFF_T_TO_LONG(len));
89a70c2000-08-28Henrik Grubbström (Grubba)  } } } #endif /* PIKE_DEBUG */ for(i = in->len; i--;) { out->str[i * 2 + 1] = in->str[i]; }
4643ea1998-10-10Henrik Grubbström (Grubba)  } out = end_shared_string(out); break; case 1: /* 16 bit characters */ /* FIXME: Should we check for 0xfffe & 0xffff here too? */ len = in->len * 2; out = begin_shared_string(len);
71f3a21998-11-22Fredrik Hübinette (Hubbe) #if (PIKE_BYTEORDER == 4321)
4643ea1998-10-10Henrik Grubbström (Grubba)  /* Big endian -- We don't need to do much... * * FIXME: Future optimization: Check if refcount is == 1, * and perform sufficient magic to be able to convert in place. */ MEMCPY(out->str, in->str, len); #else /* Other endianness, may need to do byte-order conversion also. */ { p_wchar1 *str1 = STR1(in); for(i = in->len; i--;) { unsigned INT32 c = str1[i];
7156611998-10-15Henrik Grubbström (Grubba)  out->str[i * 2 + 1] = c & 0xff;
66b11d1998-10-15Henrik Grubbström (Grubba)  out->str[i * 2] = c >> 8;
4643ea1998-10-10Henrik Grubbström (Grubba)  } } #endif out = end_shared_string(out); break; case 2: /* 32 bit characters -- Is someone writing in Klingon? */ { p_wchar2 *str2 = STR2(in);
93b7202000-08-14Henrik Grubbström (Grubba)  ptrdiff_t j;
01c1081998-10-10Henrik Grubbström (Grubba)  len = in->len * 2;
4643ea1998-10-10Henrik Grubbström (Grubba)  /* Check how many extra wide characters there are. */ for(i = in->len; i--;) { if (str2[i] > 0xfffd) { if (str2[i] < 0x10000) { /* 0xfffe: Byte-order detection illegal character. * 0xffff: Illegal character. */
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("string_to_unicode(): Illegal character 0x%04x (index %ld) "
69bb402000-08-17Henrik Grubbström (Grubba)  "is not a Unicode character.", str2[i], PTRDIFF_T_TO_LONG(i));
4643ea1998-10-10Henrik Grubbström (Grubba)  } if (str2[i] > 0x10ffff) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("string_to_unicode(): Character 0x%08x (index %ld) "
b99d882003-05-15Martin Stjernholm  "is out of range (0x00000000..0x0010ffff).",
69bb402000-08-17Henrik Grubbström (Grubba)  str2[i], PTRDIFF_T_TO_LONG(i));
4643ea1998-10-10Henrik Grubbström (Grubba)  } /* Extra wide characters take two unicode characters in space. * ie One unicode character extra. */ len += 2; } } out = begin_shared_string(len);
01c1081998-10-10Henrik Grubbström (Grubba)  j = len;
4643ea1998-10-10Henrik Grubbström (Grubba)  for(i = in->len; i--;) { unsigned INT32 c = str2[i]; j -= 2; if (c > 0xffff) { /* Use surrogates */ c -= 0x10000; out->str[j + 1] = c & 0xff; out->str[j] = 0xdc | ((c >> 8) & 0x03); j -= 2; c >>= 10; c |= 0xd800; } out->str[j + 1] = c & 0xff; out->str[j] = c >> 8; }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
4643ea1998-10-10Henrik Grubbström (Grubba)  if (j) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("string_to_unicode(): Indexing error: len:%ld, j:%ld.\n",
69bb402000-08-17Henrik Grubbström (Grubba)  PTRDIFF_T_TO_LONG(len), PTRDIFF_T_TO_LONG(j));
4643ea1998-10-10Henrik Grubbström (Grubba)  }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #endif /* PIKE_DEBUG */
4643ea1998-10-10Henrik Grubbström (Grubba)  out = end_shared_string(out); } break; default:
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("string_to_unicode(): Bad string shift: %d!\n", in->size_shift);
4643ea1998-10-10Henrik Grubbström (Grubba)  break; } pop_n_elems(args); push_string(out); }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl string unicode_to_string(string s) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Converts an UTF16 byte-stream into a string.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @note
554e222001-05-06Henrik Grubbström (Grubba)  *! This function did not decode surrogates in Pike 7.2 and earlier.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
a056042001-10-28Martin Nilsson  *! @[Locale.Charset.decoder()], @[string_to_unicode()], @[string_to_utf8()],
554e222001-05-06Henrik Grubbström (Grubba)  *! @[utf8_to_string()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_unicode_to_string(INT32 args)
4643ea1998-10-10Henrik Grubbström (Grubba) { struct pike_string *in; struct pike_string *out = NULL;
f272792001-04-18Marcus Comstedt  ptrdiff_t len, i, num_surrogates = 0; int swab=0; p_wchar1 surr1, surr2, surrmask, *str0;
4643ea1998-10-10Henrik Grubbström (Grubba)  get_all_args("unicode_to_string", args, "%S", &in); if (in->len & 1) {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  bad_arg_error("unicode_to_string", Pike_sp-args, args, 1, "string", Pike_sp-args,
d0d01b1999-03-20Henrik Grubbström (Grubba)  "String length is odd.\n");
4643ea1998-10-10Henrik Grubbström (Grubba)  }
f272792001-04-18Marcus Comstedt  /* Check byteorder of UTF data */ str0 = (p_wchar1 *)in->str; len = in->len;
2f1f3e2001-05-03Henrik Grubbström (Grubba)  if (len && (str0[0] == 0xfeff)) {
f272792001-04-18Marcus Comstedt  /* Correct byte order mark. No swap necessary. */ swab = 0; str0 ++; len -= 2;
2f1f3e2001-05-03Henrik Grubbström (Grubba)  } else if (len && (str0[0] == 0xfffe)) {
f272792001-04-18Marcus Comstedt  /* Reversed byte order mark. Need to swap. */ swab = 1; str0 ++; len -= 2; } else { /* No byte order mark. Need to swap unless big endian */
71f3a21998-11-22Fredrik Hübinette (Hubbe) #if (PIKE_BYTEORDER == 4321)
f272792001-04-18Marcus Comstedt  swab = 0;
4643ea1998-10-10Henrik Grubbström (Grubba) #else
f272792001-04-18Marcus Comstedt  swab = 1; #endif /* PIKE_BYTEORDER == 4321 */ } /* Indentify surrogates by pre-swapped bitmasks, for efficiency */ if (swab) { surr1 = 0xd8; surr2 = 0xdc; surrmask = 0xfc; } else { surr1 = 0xd800; surr2 = 0xdc00; surrmask = 0xfc00; } /* Count number of surrogates */ for (i = len; i >= 4; i -= 2, str0++) if ( (str0[0]&surrmask) == surr1 && (str0[1]&surrmask) == surr2 ) num_surrogates ++; /* Move str0 past the last word */ str0++; len = len / 2 - num_surrogates; out = begin_wide_shared_string(len, (num_surrogates? 2 : 1)); if (!swab) { /* Native endian */ if (num_surrogates) { /* Convert surrogates */ p_wchar2 *str2 = STR2(out); for (i = len; i--; --str0) if ((str0[-1]&surrmask) == surr2 && num_surrogates && (str0[-2]&surrmask) == surr1) { str2[i] = ((str0[-2]&0x3ff)<<10) + (str0[-1]&0x3ff) + 0x10000;
4643ea1998-10-10Henrik Grubbström (Grubba) 
f272792001-04-18Marcus Comstedt  --str0; --num_surrogates; } else str2[i] = str0[-1]; } else /* * FIXME: Future optimization: Perform sufficient magic * to do the conversion in place if the ref-count is == 1. */ MEMCPY(out->str, (char *)(str0-len), len*2); } else { /* Reverse endian */ if (num_surrogates) { /* Convert surrogates */ p_wchar2 *str2 = STR2(out);
2f1f3e2001-05-03Henrik Grubbström (Grubba)  for (i = len; i--; --str0) {
f272792001-04-18Marcus Comstedt  if ((str0[-1]&surrmask) == surr2 && num_surrogates && (str0[-2]&surrmask) == surr1) {
2f1f3e2001-05-03Henrik Grubbström (Grubba) #if (PIKE_BYTEORDER == 4321)
bdafb52001-05-08Henrik Grubbström (Grubba)  str2[i] = ((((unsigned char *)str0)[-3]&3)<<18) + (((unsigned char *)str0)[-4]<<10) + ((((unsigned char *)str0)[-1]&3)<<8) + ((unsigned char *)str0)[-2] +
2f1f3e2001-05-03Henrik Grubbström (Grubba)  0x10000; #else /* PIKE_BYTEORDER != 4321 */
f272792001-04-18Marcus Comstedt  str2[i] = ((((unsigned char *)str0)[-4]&3)<<18) + (((unsigned char *)str0)[-3]<<10) + ((((unsigned char *)str0)[-2]&3)<<8) + ((unsigned char *)str0)[-1] + 0x10000;
2f1f3e2001-05-03Henrik Grubbström (Grubba) #endif /* PIKE_BYTEORDER == 4321 */
f272792001-04-18Marcus Comstedt  --str0; --num_surrogates;
2f1f3e2001-05-03Henrik Grubbström (Grubba)  } else { #if (PIKE_BYTEORDER == 4321) str2[i] = (((unsigned char *)str0)[-1]<<8) + ((unsigned char *)str0)[-2]; #else /* PIKE_BYTEORDER != 4321 */
f272792001-04-18Marcus Comstedt  str2[i] = (((unsigned char *)str0)[-2]<<8) + ((unsigned char *)str0)[-1];
2f1f3e2001-05-03Henrik Grubbström (Grubba) #endif /* PIKE_BYTEORDER == 4321 */ } }
f272792001-04-18Marcus Comstedt  } else { /* No surrogates */ p_wchar1 *str1 = STR1(out);
2f1f3e2001-05-03Henrik Grubbström (Grubba)  for (i = len; i--; --str0) { #if (PIKE_BYTEORDER == 4321) str1[i] = (((unsigned char *)str0)[-1]<<8) + ((unsigned char *)str0)[-2]; #else /* PIKE_BYTEORDER != 4321 */
f272792001-04-18Marcus Comstedt  str1[i] = (((unsigned char *)str0)[-2]<<8) + ((unsigned char *)str0)[-1];
2f1f3e2001-05-03Henrik Grubbström (Grubba) #endif /* PIKE_BYTEORDER == 4321 */ }
4643ea1998-10-10Henrik Grubbström (Grubba)  } } out = end_shared_string(out); pop_n_elems(args); push_string(out); }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl string string_to_utf8(string s) *! @decl string string_to_utf8(string s, int extended) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Converts a string into an UTF8 compliant byte-stream.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @note
554e222001-05-06Henrik Grubbström (Grubba)  *! Throws an error if characters not valid in an UTF8 stream are *! encountered. Valid characters are in the range 0x00000000 - 0x7fffffff.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! If @[extended] is 1, characters in the range 0x80000000-0xfffffffff *! will also be accepted, and encoded using a non-standard UTF8 extension.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
a056042001-10-28Martin Nilsson  *! @[Locale.Charset.encoder()], @[string_to_unicode()],
554e222001-05-06Henrik Grubbström (Grubba)  *! @[unicode_to_string()], @[utf8_to_string()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
77cc592003-11-14Martin Stjernholm PMOD_EXPORT void f_string_to_utf8(INT32 args)
be40771998-10-15Henrik Grubbström (Grubba) {
93b7202000-08-14Henrik Grubbström (Grubba)  ptrdiff_t len;
be40771998-10-15Henrik Grubbström (Grubba)  struct pike_string *in; struct pike_string *out;
69bb402000-08-17Henrik Grubbström (Grubba)  ptrdiff_t i,j;
2adf002004-02-29Martin Stjernholm  INT_TYPE extended = 0;
be40771998-10-15Henrik Grubbström (Grubba) 
2adf002004-02-29Martin Stjernholm  get_all_args("string_to_utf8", args, "%W.%i", &in, &extended);
be40771998-10-15Henrik Grubbström (Grubba)  len = in->len; for(i=0; i < in->len; i++) { unsigned INT32 c = index_shared_string(in, i); if (c & ~0x7f) { /* 8bit or more. */ len++; if (c & ~0x7ff) { /* 12bit or more. */ len++; if (c & ~0xffff) { /* 17bit or more. */ len++; if (c & ~0x1fffff) { /* 22bit or more. */ len++; if (c & ~0x3ffffff) { /* 27bit or more. */ len++; if (c & ~0x7fffffff) { /* 32bit or more. */
cf03f91998-10-31Henrik Grubbström (Grubba)  if (!extended) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("string_to_utf8(): "
d1cac52000-09-07Henrik Grubbström (Grubba)  "Value 0x%08x (index %ld) is larger than 31 bits.\n", c, PTRDIFF_T_TO_LONG(i));
cf03f91998-10-31Henrik Grubbström (Grubba)  }
be40771998-10-15Henrik Grubbström (Grubba)  len++; /* FIXME: Needs fixing when we get 64bit chars... */ } } } } } } } if (len == in->len) {
8e3f351998-10-23Henrik Grubbström (Grubba)  /* 7bit string -- already valid utf8. */
be40771998-10-15Henrik Grubbström (Grubba)  pop_n_elems(args - 1); return; } out = begin_shared_string(len); for(i=j=0; i < in->len; i++) { unsigned INT32 c = index_shared_string(in, i); if (!(c & ~0x7f)) { /* 7bit */ out->str[j++] = c; } else if (!(c & ~0x7ff)) { /* 11bit */ out->str[j++] = 0xc0 | (c >> 6); out->str[j++] = 0x80 | (c & 0x3f); } else if (!(c & ~0xffff)) { /* 16bit */ out->str[j++] = 0xe0 | (c >> 12); out->str[j++] = 0x80 | ((c >> 6) & 0x3f); out->str[j++] = 0x80 | (c & 0x3f); } else if (!(c & ~0x1fffff)) { /* 21bit */ out->str[j++] = 0xf0 | (c >> 18); out->str[j++] = 0x80 | ((c >> 12) & 0x3f); out->str[j++] = 0x80 | ((c >> 6) & 0x3f); out->str[j++] = 0x80 | (c & 0x3f); } else if (!(c & ~0x3ffffff)) { /* 26bit */ out->str[j++] = 0xf8 | (c >> 24); out->str[j++] = 0x80 | ((c >> 18) & 0x3f); out->str[j++] = 0x80 | ((c >> 12) & 0x3f); out->str[j++] = 0x80 | ((c >> 6) & 0x3f); out->str[j++] = 0x80 | (c & 0x3f); } else if (!(c & ~0x7fffffff)) { /* 31bit */ out->str[j++] = 0xfc | (c >> 30); out->str[j++] = 0x80 | ((c >> 24) & 0x3f); out->str[j++] = 0x80 | ((c >> 18) & 0x3f); out->str[j++] = 0x80 | ((c >> 12) & 0x3f); out->str[j++] = 0x80 | ((c >> 6) & 0x3f); out->str[j++] = 0x80 | (c & 0x3f); } else {
ed65901998-10-31Henrik Grubbström (Grubba)  /* This and onwards is extended UTF-8 encoding. */
be40771998-10-15Henrik Grubbström (Grubba)  /* 32 - 36bit */
1f88bf2001-09-24Henrik Grubbström (Grubba)  out->str[j++] = DO_NOT_WARN((char)0xfe);
be40771998-10-15Henrik Grubbström (Grubba)  out->str[j++] = 0x80 | ((c >> 30) & 0x3f); out->str[j++] = 0x80 | ((c >> 24) & 0x3f); out->str[j++] = 0x80 | ((c >> 18) & 0x3f); out->str[j++] = 0x80 | ((c >> 12) & 0x3f); out->str[j++] = 0x80 | ((c >> 6) & 0x3f); out->str[j++] = 0x80 | (c & 0x3f); } }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
be40771998-10-15Henrik Grubbström (Grubba)  if (len != j) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("string_to_utf8(): Calculated and actual lengths differ: "
69bb402000-08-17Henrik Grubbström (Grubba)  "%ld != %ld\n", PTRDIFF_T_TO_LONG(len), PTRDIFF_T_TO_LONG(j));
be40771998-10-15Henrik Grubbström (Grubba)  }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #endif /* PIKE_DEBUG */
be40771998-10-15Henrik Grubbström (Grubba)  out = end_shared_string(out); pop_n_elems(args); push_string(out); }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl string utf8_to_string(string s) *! @decl string utf8_to_string(string s, int extended) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Converts an UTF8 byte-stream into a string.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @note
554e222001-05-06Henrik Grubbström (Grubba)  *! Throws an error if the stream is not a legal UFT8 byte-stream.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Accepts and decodes the extension used by @[string_to_utf8()], if
cbe8c92003-04-07Martin Nilsson  *! @[extended] is @expr{1@}.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
a056042001-10-28Martin Nilsson  *! @[Locale.Charset.encoder()], @[string_to_unicode()], @[string_to_utf8()],
554e222001-05-06Henrik Grubbström (Grubba)  *! @[unicode_to_string()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_utf8_to_string(INT32 args)
be40771998-10-15Henrik Grubbström (Grubba) { struct pike_string *in; struct pike_string *out; int len = 0; int shift = 0; int i,j;
2adf002004-02-29Martin Stjernholm  INT_TYPE extended = 0;
be40771998-10-15Henrik Grubbström (Grubba) 
2adf002004-02-29Martin Stjernholm  get_all_args("utf8_to_string", args, "%S.%i", &in, &extended);
ed65901998-10-31Henrik Grubbström (Grubba) 
be40771998-10-15Henrik Grubbström (Grubba)  for(i=0; i < in->len; i++) { unsigned int c = ((unsigned char *)in->str)[i]; len++; if (c & 0x80) { int cont = 0; if ((c & 0xc0) == 0x80) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("utf8_to_string(): "
be40771998-10-15Henrik Grubbström (Grubba)  "Unexpected continuation block 0x%02x at index %d.\n", c, i); } if ((c & 0xe0) == 0xc0) { /* 11bit */ cont = 1; if (c & 0x1c) { if (shift < 1) { shift = 1; } } } else if ((c & 0xf0) == 0xe0) { /* 16bit */ cont = 2; if (shift < 1) { shift = 1; } } else { shift = 2; if ((c & 0xf8) == 0xf0) { /* 21bit */ cont = 3; } else if ((c & 0xfc) == 0xf8) { /* 26bit */ cont = 4; } else if ((c & 0xfe) == 0xfc) { /* 31bit */ cont = 5; } else if (c == 0xfe) { /* 36bit */
ed65901998-10-31Henrik Grubbström (Grubba)  if (!extended) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("utf8_to_string(): "
ed65901998-10-31Henrik Grubbström (Grubba)  "Character 0xfe at index %d when not in extended mode.\n", i); }
be40771998-10-15Henrik Grubbström (Grubba)  cont = 6; } else {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("utf8_to_string(): "
be40771998-10-15Henrik Grubbström (Grubba)  "Unexpected character 0xff at index %d.\n", i); } } while(cont--) { i++; if (i >= in->len) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("utf8_to_string(): Truncated UTF8 sequence.\n");
be40771998-10-15Henrik Grubbström (Grubba)  } c = ((unsigned char *)(in->str))[i]; if ((c & 0xc0) != 0x80) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("utf8_to_string(): "
be40771998-10-15Henrik Grubbström (Grubba)  "Expected continuation character at index %d (got 0x%02x).\n", i, c); } } } } if (len == in->len) { /* 7bit in == 7bit out */ pop_n_elems(args-1); return; } out = begin_wide_shared_string(len, shift); for(j=i=0; i < in->len; i++) { unsigned int c = ((unsigned char *)in->str)[i]; if (c & 0x80) { int cont = 0; /* NOTE: The tests aren't as paranoid here, since we've * already tested the string above. */ if ((c & 0xe0) == 0xc0) { /* 11bit */ cont = 1; c &= 0x1f; } else if ((c & 0xf0) == 0xe0) { /* 16bit */ cont = 2; c &= 0x0f; } else if ((c & 0xf8) == 0xf0) { /* 21bit */ cont = 3; c &= 0x07; } else if ((c & 0xfc) == 0xf8) { /* 26bit */ cont = 4; c &= 0x03; } else if ((c & 0xfe) == 0xfc) { /* 31bit */ cont = 5; c &= 0x01; } else { /* 36bit */ cont = 6; c = 0; } while(cont--) { unsigned INT32 c2 = ((unsigned char *)(in->str))[++i] & 0x3f; c = (c << 6) | c2; } } low_set_index(out, j++, c); }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
be40771998-10-15Henrik Grubbström (Grubba)  if (j != len) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("utf8_to_string(): Calculated and actual lengths differ: %d != %d\n",
be40771998-10-15Henrik Grubbström (Grubba)  len, j); }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #endif /* PIKE_DEBUG */
be40771998-10-15Henrik Grubbström (Grubba)  out = end_shared_string(out); pop_n_elems(args); push_string(out); }
7535f82001-01-08Henrik Grubbström (Grubba) /*! @decl string __parse_pike_type(string t)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
aa0bdf1999-11-08Per Hedbor static void f_parse_pike_type( INT32 args ) {
babd872001-02-23Henrik Grubbström (Grubba)  struct pike_type *t;
1f88bf2001-09-24Henrik Grubbström (Grubba) 
babd872001-02-23Henrik Grubbström (Grubba)  if( !args || Pike_sp[-1].type != T_STRING ||
edf4d02000-07-06Fredrik Hübinette (Hubbe)  Pike_sp[-1].u.string->size_shift )
9c1a7b2001-01-08Henrik Grubbström (Grubba)  Pike_error( "__parse_pike_type requires a 8bit string as its first argument\n" );
babd872001-02-23Henrik Grubbström (Grubba)  t = parse_type( (char *)STR0(Pike_sp[-1].u.string) );
aa0bdf1999-11-08Per Hedbor  pop_stack();
babd872001-02-23Henrik Grubbström (Grubba) 
986b522001-03-17Henrik Grubbström (Grubba)  push_string(type_to_string(t)); free_type(t);
aa0bdf1999-11-08Per Hedbor }
19febd2002-02-14Martin Nilsson /*! @decl mapping (string:mixed) all_constants()
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Returns a mapping containing all global constants, indexed on the name *! of the constant, and with the value of the constant as value.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[add_constant()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_all_constants(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) { pop_n_elems(args);
0e88611998-04-16Fredrik Hübinette (Hubbe)  ref_push_mapping(get_builtin_constants());
5267b71995-08-09Fredrik Hübinette (Hubbe) }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl array allocate(int size)
2523ce2003-04-28Martin Stjernholm  *! @decl array allocate(int size, mixed init)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
2523ce2003-04-28Martin Stjernholm  *! Allocate an array of @[size] elements. If @[init] is specified *! then each element is initialized by copying that value *! recursively.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[sizeof()], @[aggregate()], @[arrayp()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_allocate(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) { INT32 size;
8267f41998-01-28Fredrik Hübinette (Hubbe)  struct array *a;
87a3422004-05-13Martin Nilsson  struct svalue *init;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
87a3422004-05-13Martin Nilsson  get_all_args("allocate", args, "%+.%*", &size, &init);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
8267f41998-01-28Fredrik Hübinette (Hubbe)  a=allocate_array(size); if(args>1) { INT32 e;
2523ce2003-04-28Martin Stjernholm  push_array (a);
87a3422004-05-13Martin Nilsson  for(e=0;e<size;e++)
2523ce2003-04-28Martin Stjernholm  copy_svalues_recursively_no_free(a->item+e, init, 1, 0); a->type_field = 1 << init->type; stack_pop_n_elems_keep_top (args); } else { a->type_field = BIT_INT; pop_n_elems(args); push_array(a);
8267f41998-01-28Fredrik Hübinette (Hubbe)  }
5267b71995-08-09Fredrik Hübinette (Hubbe) }
0ee38f2002-05-11Martin Stjernholm /*! @decl object this_object(void|int level);
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Returns the object we are currently evaluating in.
0ee38f2002-05-11Martin Stjernholm  *! *! @[level] might be used to access the object of a surrounding *! class: The object at level 0 is the current object, the object
aa7e422003-08-03Martin Stjernholm  *! at level 1 is the one belonging to the class that surrounds *! the class that the object comes from, and so on. *! *! @note *! As opposed to a qualified @expr{this@} reference such as *! @expr{global::this@}, this function doesn't always access the *! objects belonging to the lexically surrounding classes. If the *! class containing the call has been inherited then the objects *! surrounding the inheriting class are accessed.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
5267b71995-08-09Fredrik Hübinette (Hubbe) void f_this_object(INT32 args) {
aa7e422003-08-03Martin Stjernholm  int level, l; struct object *o;
0ee38f2002-05-11Martin Stjernholm  if (args) { if (Pike_sp[-args].type != T_INT || Pike_sp[-args].u.integer < 0) SIMPLE_BAD_ARG_ERROR ("this_object", 1, "a non-negative integer"); level = Pike_sp[-args].u.integer; } else level = 0;
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args);
aa7e422003-08-03Martin Stjernholm  o = Pike_fp->current_object; for (l = 0; l < level; l++) { struct program *p = o->prog; if (!p) Pike_error ("Object %d level(s) up is destructed - cannot get the parent.\n", l); if (!(p->flags & PROGRAM_USES_PARENT)) /* FIXME: Ought to write out the object here. */ Pike_error ("Object %d level(s) up lacks parent reference.\n", l); o = PARENT_INFO(o)->parent;
cb22561995-10-11Fredrik Hübinette (Hubbe)  }
aa7e422003-08-03Martin Stjernholm  ref_push_object(o);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
0ee38f2002-05-11Martin Stjernholm static node *optimize_this_object(node *n)
b62ab01999-12-12Henrik Grubbström (Grubba) {
aa7e422003-08-03Martin Stjernholm  int level = 0;
0ee38f2002-05-11Martin Stjernholm  if (CDR (n)) { struct program_state *state = Pike_compiler; if (CDR (n)->token != F_CONSTANT) { /* Not a constant expression. Make sure there are parent * pointers all the way. */ int i; for (i = 0; i < compilation_depth; i++, state = state->previous) state->new_program->flags |= PROGRAM_USES_PARENT | PROGRAM_NEEDS_PARENT; return NULL; } else {
aa7e422003-08-03Martin Stjernholm  int i;
0ee38f2002-05-11Martin Stjernholm #ifdef PIKE_DEBUG if (CDR (n)->u.sval.type != T_INT || CDR (n)->u.sval.u.integer < 0)
5aad932002-08-15Marcus Comstedt  Pike_fatal ("The type check for this_object() failed.\n");
0ee38f2002-05-11Martin Stjernholm #endif level = CDR (n)->u.sval.u.integer;
073ccf2003-08-04Henrik Grubbström (Grubba)  for (i = MINIMUM(level, compilation_depth); i; i--, state = state->previous) { state->new_program->flags |= PROGRAM_USES_PARENT | PROGRAM_NEEDS_PARENT; }
0ee38f2002-05-11Martin Stjernholm  } }
aa7e422003-08-03Martin Stjernholm  /* We can only improve the type when accessing the innermost object: * Since this_object always follows the object pointers it might not * access the lexically surrounding objects. Thus the * PROGRAM_USES_PARENT stuff above is a bit of a long shot, but it's * better than nothing. */ if (!level) { free_type(n->type); type_stack_mark(); /* We are rather sure that we contain ourselves... */ /* push_object_type(1, Pike_compiler->new_program->id); */ /* But it did not work yet, so... */ push_object_type(0, Pike_compiler->new_program->id); n->type = pop_unfinished_type(); if (n->parent) { n->parent->node_info |= OPT_TYPE_NOT_FIXED; }
b62ab01999-12-12Henrik Grubbström (Grubba)  }
aa7e422003-08-03Martin Stjernholm 
b62ab01999-12-12Henrik Grubbström (Grubba)  return NULL; }
0811472001-07-02Fredrik Hübinette (Hubbe) static int generate_this_object(node *n) {
0ee38f2002-05-11Martin Stjernholm  int level; if (CDR (n)) { if (CDR (n)->token != F_CONSTANT) /* Not a constant expression. Make a call to f_this_object. */ return 0; else { #ifdef PIKE_DEBUG if (CDR (n)->u.sval.type != T_INT || CDR (n)->u.sval.u.integer < 0)
5aad932002-08-15Marcus Comstedt  Pike_fatal ("The type check for this_object() failed.\n");
0ee38f2002-05-11Martin Stjernholm #endif level = CDR (n)->u.sval.u.integer; } } else level = 0; emit1(F_THIS_OBJECT, level);
0811472001-07-02Fredrik Hübinette (Hubbe)  return 1; }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl void throw(mixed value) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Throw @[value] to a waiting @[catch].
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! If no @[catch] is waiting the global error handling will send the *! value to @[master()->handle_error()].
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! If you throw an array with where the first index contains an error *! message and the second index is a backtrace, (the output from *! @[backtrace()]) then it will be treated exactly like a real error *! by overlying functions.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[catch]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_throw(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) { if(args < 1)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_TOO_FEW_ARGS_ERROR("throw", 1);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  assign_svalue(&throw_value,Pike_sp-args);
864d3c1998-01-29Fredrik Hübinette (Hubbe)  pop_n_elems(args);
641d5c1998-04-09Fredrik Hübinette (Hubbe)  throw_severity=0;
dc7cc91998-01-14Fredrik Hübinette (Hubbe)  pike_throw();
5267b71995-08-09Fredrik Hübinette (Hubbe) }
19e2c32004-03-02Martin Nilsson /*! @decl void exit(int returncode, void|string fmt, mixed ... extra)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Exit the whole Pike program with the given @[returncode].
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
cbe8c92003-04-07Martin Nilsson  *! Using @[exit()] with any other value than @expr{0@} (zero) indicates *! that something went wrong during execution. See your system manuals *! for more information about return codes.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
b5ef7d2004-01-11Martin Nilsson  *! The arguments after the @[returncode] will be used for a call to *! @[werror] to output a message on stderr. *!
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[_exit()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_exit(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
b4c5de1999-03-25Fredrik Hübinette (Hubbe)  static int in_exit=0;
8111162003-09-07Martin Nilsson  ASSERT_SECURITY_ROOT("exit");
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(args < 1)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_TOO_FEW_ARGS_ERROR("exit", 1);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[-args].type != T_INT)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("exit", 1, "int");
5267b71995-08-09Fredrik Hübinette (Hubbe) 
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  if(in_exit) Pike_error("exit already called!\n");
b4c5de1999-03-25Fredrik Hübinette (Hubbe)  in_exit=1;
d8e90a2004-05-09Martin Nilsson  if(args>1 && Pike_sp[1-args].type==T_STRING) {
b5ef7d2004-01-11Martin Nilsson  f_werror(args-1);
d8e90a2004-05-09Martin Nilsson  args=1; }
b5ef7d2004-01-11Martin Nilsson 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  assign_svalue(&throw_value, Pike_sp-args);
61e9a01998-01-25Fredrik Hübinette (Hubbe)  throw_severity=THROW_EXIT; pike_throw();
5267b71995-08-09Fredrik Hübinette (Hubbe) }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl void _exit(int returncode) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function does the same as @[exit], but doesn't bother to clean *! up the Pike interpreter before exiting. This means that no destructors *! will be called, caches will not be flushed, file locks might not be *! released, and databases might not be closed properly.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Use with extreme caution.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[exit()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
608d731998-03-20Fredrik Hübinette (Hubbe) void f__exit(INT32 args) {
b2acc92004-05-13Martin Nilsson  int code;
8111162003-09-07Martin Nilsson  ASSERT_SECURITY_ROOT("_exit");
b2acc92004-05-13Martin Nilsson  get_all_args("_exit", args, "%i", &code);
608d731998-03-20Fredrik Hübinette (Hubbe) 
d9a93b2001-07-01Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG { /* This will allow -p to work with _exit -Hubbe */
143d882003-11-14Martin Stjernholm  exit_opcodes();
d9a93b2001-07-01Fredrik Hübinette (Hubbe)  } #endif
b2acc92004-05-13Martin Nilsson  exit(code);
608d731998-03-20Fredrik Hübinette (Hubbe) }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl int time(); *! @decl int time(int(1..1) one) *! @decl float time(int(2..) t) *!
df0f872003-04-14Martin Stjernholm  *! This function returns the number of seconds since 00:00:00 UTC, 1 Jan 1970.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
93af2d2003-10-31Martin Stjernholm  *! The second syntax does not query the system for the current *! time. Instead the latest done by the pike process is returned *! again. That's slightly faster but can be wildly inaccurate. Pike *! queries the time internally when a thread has waited for *! something, typically in @[sleep] or in a backend (see *! @[Pike.Backend]).
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! The third syntax can be used to measure time more preciely than one *! second. It return how many seconds has passed since @[t]. The precision *! of this function varies from system to system.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
5ef9052003-01-13Martin Stjernholm  *! @[ctime()], @[localtime()], @[mktime()], @[gmtime()],
2cccd32003-01-13Martin Stjernholm  *! @[System.gettimeofday], @[gethrtime]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_time(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
7b52a01998-03-10Henrik Grubbström (Grubba)  if(!args)
d0e6741998-07-15Fredrik Hübinette (Hubbe)  {
7b52a01998-03-10Henrik Grubbström (Grubba)  GETTIMEOFDAY(&current_time);
d0e6741998-07-15Fredrik Hübinette (Hubbe)  }else{
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[-args].type == T_INT && Pike_sp[-args].u.integer > 1)
d0e6741998-07-15Fredrik Hübinette (Hubbe)  { struct timeval tmp; GETTIMEOFDAY(&current_time);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  tmp.tv_sec=Pike_sp[-args].u.integer;
d0e6741998-07-15Fredrik Hübinette (Hubbe)  tmp.tv_usec=0; my_subtract_timeval(&tmp,&current_time); pop_n_elems(args);
65a5492000-08-10Per Hedbor  push_float( - (FLOAT_TYPE)tmp.tv_sec-((FLOAT_TYPE)tmp.tv_usec)/1000000 );
d0e6741998-07-15Fredrik Hübinette (Hubbe)  return; } } pop_n_elems(args);
7b52a01998-03-10Henrik Grubbström (Grubba)  push_int(current_time.tv_sec);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl string crypt(string password) *! @decl int(0..1) crypt(string typed_password, string crypted_password) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function crypts and verifies a short string (only the first *! 8 characters are significant).
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! The first syntax crypts the string @[password] into something that *! is hopefully hard to decrypt.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! The second syntax is used to verify @[typed_password] against
cbe8c92003-04-07Martin Nilsson  *! @[crypted_password], and returns @expr{1@} if they match, and *! @expr{0@} (zero) otherwise.
b2acc92004-05-13Martin Nilsson  *! *! @note *! Note that strings containing null characters will only be *! processed up until the null character.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_crypt(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) { char salt[2];
b2acc92004-05-13Martin Nilsson  char *ret, *pwd, *saltp;
5267b71995-08-09Fredrik Hübinette (Hubbe)  char *choise = "cbhisjKlm4k65p7qrJfLMNQOPxwzyAaBDFgnoWXYCZ0123tvdHueEGISRTUV89./";
b2acc92004-05-13Martin Nilsson  get_all_args("crypt", args, "%s.%s", &pwd, &saltp);
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(args>1) {
b2acc92004-05-13Martin Nilsson  if( Pike_sp[1-args].u.string->len < 2 )
0f6deb1997-08-06Fredrik Hübinette (Hubbe)  { pop_n_elems(args); push_int(0); return; }
5267b71995-08-09Fredrik Hübinette (Hubbe)  } else {
99e2121996-09-23Fredrik Hübinette (Hubbe)  unsigned int foo; /* Sun CC want's this :( */ foo=my_rand();
93b7202000-08-14Henrik Grubbström (Grubba)  salt[0] = choise[foo % (size_t) strlen(choise)];
99e2121996-09-23Fredrik Hübinette (Hubbe)  foo=my_rand();
93b7202000-08-14Henrik Grubbström (Grubba)  salt[1] = choise[foo % (size_t) strlen(choise)];
8beaf71996-04-13Fredrik Hübinette (Hubbe)  saltp=salt;
5267b71995-08-09Fredrik Hübinette (Hubbe)  } #ifdef HAVE_CRYPT
b2acc92004-05-13Martin Nilsson  ret = (char *)crypt(pwd, saltp);
5267b71995-08-09Fredrik Hübinette (Hubbe) #else #ifdef HAVE__CRYPT
b2acc92004-05-13Martin Nilsson  ret = (char *)_crypt(pwd, saltp);
5267b71995-08-09Fredrik Hübinette (Hubbe) #else
b2acc92004-05-13Martin Nilsson  ret = pwd;
5267b71995-08-09Fredrik Hübinette (Hubbe) #endif #endif if(args < 2) { pop_n_elems(args);
f0e6f12003-12-06Martin Nilsson  push_text(ret);
5267b71995-08-09Fredrik Hübinette (Hubbe)  }else{ int i;
b2acc92004-05-13Martin Nilsson  i=!strcmp(ret,saltp);
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_int(i); } }
c8bb3c2004-04-20Martin Nilsson /*! @decl void destruct(void|object o)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Mark an object as destructed.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
c8bb3c2004-04-20Martin Nilsson  *! Calls @expr{o->destroy()@}, and then clears all variables in the *! object. If no argument is given, the current object is destructed.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! All pointers and function pointers to this object will become zero. *! The destructed object will be freed from memory as soon as possible.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_destruct(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) { struct object *o; if(args) {
b5d71b2001-06-09Henrik Grubbström (Grubba)  if(Pike_sp[-args].type != T_OBJECT) { if ((Pike_sp[-args].type == T_INT) && (!Pike_sp[-args].u.integer)) { pop_n_elems(args); return; }
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("destruct", 1, "object");
b5d71b2001-06-09Henrik Grubbström (Grubba)  }
e99c7a1999-10-29Martin Stjernholm 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  o=Pike_sp[-args].u.object;
cb22561995-10-11Fredrik Hübinette (Hubbe)  }else{
b5d71b2001-06-09Henrik Grubbström (Grubba)  if(!Pike_fp) { PIKE_ERROR("destruct", "Destruct called without argument from callback function.\n", Pike_sp, args); }
edf4d02000-07-06Fredrik Hübinette (Hubbe)  o=Pike_fp->current_object;
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
4d6d781999-11-14Martin Stjernholm  if (o->prog && o->prog->flags & PROGRAM_NO_EXPLICIT_DESTRUCT)
b5d71b2001-06-09Henrik Grubbström (Grubba)  PIKE_ERROR("destruct", "Object can't be destructed explicitly.\n", Pike_sp, args);
803e641999-04-02Fredrik Hübinette (Hubbe) #ifdef PIKE_SECURITY if(!CHECK_DATA_SECURITY(o, SECURITY_BIT_DESTRUCT))
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Destruct permission denied.\n");
803e641999-04-02Fredrik Hübinette (Hubbe) #endif
54717e2001-06-28Fredrik Hübinette (Hubbe)  debug_malloc_touch(o);
5267b71995-08-09Fredrik Hübinette (Hubbe)  destruct(o);
cb22561995-10-11Fredrik Hübinette (Hubbe)  pop_n_elems(args);
44138c2000-08-02Fredrik Hübinette (Hubbe)  destruct_objects_to_destruct();
5267b71995-08-09Fredrik Hübinette (Hubbe) }
937c462001-02-06Henrik Grubbström (Grubba) /*! @decl array indices(string|array|mapping|multiset|object x)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Return an array of all valid indices for the value @[x].
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
b2acc92004-05-13Martin Nilsson  *! For strings and arrays this is simply an array of ascending *! numbers.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! For mappings and multisets, the array may contain any value.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
b2acc92004-05-13Martin Nilsson  *! For objects which define @[lfun::_indices()] that return value *! will be used.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
b2acc92004-05-13Martin Nilsson  *! For other objects an array with all non-static symbols will be *! returned.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[values()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_indices(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
93b7202000-08-14Henrik Grubbström (Grubba)  ptrdiff_t size;
cb787a2000-08-24Henrik Grubbström (Grubba)  struct array *a = NULL;
93b7202000-08-14Henrik Grubbström (Grubba) 
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(args < 1)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_TOO_FEW_ARGS_ERROR("indices", 1);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  switch(Pike_sp[-args].type)
5267b71995-08-09Fredrik Hübinette (Hubbe)  { case T_STRING:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  size=Pike_sp[-args].u.string->len;
5267b71995-08-09Fredrik Hübinette (Hubbe)  goto qjump; case T_ARRAY:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  size=Pike_sp[-args].u.array->size;
5267b71995-08-09Fredrik Hübinette (Hubbe)  qjump:
99946c1996-02-17Fredrik Hübinette (Hubbe)  a=allocate_array_no_init(size,0);
5c8e891995-10-29Fredrik Hübinette (Hubbe)  while(--size>=0)
99946c1996-02-17Fredrik Hübinette (Hubbe)  {
2523ce2003-04-28Martin Stjernholm  /* Elements are already integers. */
63540d2000-08-15Henrik Grubbström (Grubba)  ITEM(a)[size].u.integer = DO_NOT_WARN((INT_TYPE)size);
99946c1996-02-17Fredrik Hübinette (Hubbe)  }
2523ce2003-04-28Martin Stjernholm  a->type_field = BIT_INT;
5267b71995-08-09Fredrik Hübinette (Hubbe)  break; case T_MAPPING:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  a=mapping_indices(Pike_sp[-args].u.mapping);
5267b71995-08-09Fredrik Hübinette (Hubbe)  break;
06983f1996-09-22Fredrik Hübinette (Hubbe)  case T_MULTISET:
5b15bb2001-12-10Martin Stjernholm  a = multiset_indices (Pike_sp[-args].u.multiset);
5267b71995-08-09Fredrik Hübinette (Hubbe)  break;
6d4c4c1995-11-06Fredrik Hübinette (Hubbe)  case T_OBJECT:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  a=object_indices(Pike_sp[-args].u.object);
6d4c4c1995-11-06Fredrik Hübinette (Hubbe)  break;
fa31451998-05-25Henrik Grubbström (Grubba)  case T_PROGRAM:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  a = program_indices(Pike_sp[-args].u.program);
fa31451998-05-25Henrik Grubbström (Grubba)  break;
0ceb871998-06-07Henrik Grubbström (Grubba)  case T_FUNCTION: {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  struct program *p = program_from_svalue(Pike_sp-args);
0ceb871998-06-07Henrik Grubbström (Grubba)  if (p) { a = program_indices(p); break; } } /* FALL THROUGH */
5267b71995-08-09Fredrik Hübinette (Hubbe)  default:
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("indices", 1, "string|array|mapping|" "multiset|object|program|function");
5267b71995-08-09Fredrik Hübinette (Hubbe)  return; /* make apcc happy */ } pop_n_elems(args); push_array(a); }
babd872001-02-23Henrik Grubbström (Grubba) /* this should probably be moved to pike_types.c or something */
4d7b181999-12-07Fredrik Hübinette (Hubbe) #define FIX_OVERLOADED_TYPE(n, lf, X) fix_overloaded_type(n,lf,X,CONSTANT_STRLEN(X))
ac04552001-02-20Henrik Grubbström (Grubba) /* FIXME: This function messes around with the implementation of pike_type, * and should probably be in pike_types.h instead. */
4d7b181999-12-07Fredrik Hübinette (Hubbe) static node *fix_overloaded_type(node *n, int lfun, const char *deftype, int deftypelen) { node **first_arg;
ac04552001-02-20Henrik Grubbström (Grubba)  struct pike_type *t, *t2;
4d7b181999-12-07Fredrik Hübinette (Hubbe)  first_arg=my_get_arg(&_CDR(n), 0); if(!first_arg) return 0; t=first_arg[0]->type; if(!t || match_types(t, object_type_string)) {
54f8ac2001-03-17Henrik Grubbström (Grubba)  /* Skip any name-nodes. */ while(t && t->type == PIKE_T_NAME) { t = t->cdr; }
3913502002-06-25Henrik Grubbström (Grubba) 
54f8ac2001-03-17Henrik Grubbström (Grubba)  /* FIXME: Ought to handle or-nodes here. */
3913502002-06-25Henrik Grubbström (Grubba)  if(t && (t->type == T_OBJECT))
4d7b181999-12-07Fredrik Hübinette (Hubbe)  {
d2361e2003-06-30Martin Stjernholm  struct program *p = id_to_program(CDR_TO_INT(t));
4d7b181999-12-07Fredrik Hübinette (Hubbe)  if(p) { int fun=FIND_LFUN(p, lfun); /* FIXME: function type string should really be compiled from * the arguments so that or:ed types are handled correctly */
46aa641999-12-29Henrik Grubbström (Grubba)  if(fun!=-1 &&
babd872001-02-23Henrik Grubbström (Grubba)  (t2 = check_call(function_type_string, ID_FROM_INT(p, fun)->type, 0)))
4d7b181999-12-07Fredrik Hübinette (Hubbe)  {
d68a072001-02-20Henrik Grubbström (Grubba)  free_type(n->type);
babd872001-02-23Henrik Grubbström (Grubba)  n->type = t2;
4d7b181999-12-07Fredrik Hübinette (Hubbe)  return 0; } } } /* If it is an object, it *may* be overloaded, we or with * the deftype.... */ #if 1 if(deftype) {
8a2a522001-03-03Henrik Grubbström (Grubba)  t2 = make_pike_type(deftype);
babd872001-02-23Henrik Grubbström (Grubba)  t = n->type; n->type = or_pike_types(t,t2,0);
d68a072001-02-20Henrik Grubbström (Grubba)  free_type(t); free_type(t2);
4d7b181999-12-07Fredrik Hübinette (Hubbe)  } #endif } return 0; /* continue optimization */ } static node *fix_indices_type(node *n) { return FIX_OVERLOADED_TYPE(n, LFUN__INDICES, tArray); } static node *fix_values_type(node *n) { return FIX_OVERLOADED_TYPE(n, LFUN__VALUES, tArray); }
aab8411999-12-07Henrik Grubbström (Grubba) static node *fix_aggregate_mapping_type(node *n) {
d68a072001-02-20Henrik Grubbström (Grubba)  struct pike_type *types[2] = { NULL, NULL };
aab8411999-12-07Henrik Grubbström (Grubba)  node *args = CDR(n);
d68a072001-02-20Henrik Grubbström (Grubba)  struct pike_type *new_type = NULL;
aab8411999-12-07Henrik Grubbström (Grubba)  #ifdef PIKE_DEBUG if (l_flag > 2) { fprintf(stderr, "Fixing type for aggregate_mapping():\n"); print_tree(n); fprintf(stderr, "Original type:"); simple_describe_type(n->type); } #endif /* PIKE_DEBUG */ if (args) { node *arg = args; int argno = 0; /* Make it easier to find... */ args->parent = 0; while(arg) {
f01a891999-12-08Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG if (l_flag > 4) { fprintf(stderr, "Searching for arg #%d...\n", argno); } #endif /* PIKE_DEBUG */
aab8411999-12-07Henrik Grubbström (Grubba)  if (arg->token == F_ARG_LIST) { if (CAR(arg)) { CAR(arg)->parent = arg; arg = CAR(arg); continue; } if (CDR(arg)) { CDR(arg)->parent = arg; arg = CDR(arg); continue; } /* Retrace */ retrace:
f01a891999-12-08Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG if (l_flag > 4) { fprintf(stderr, "Retracing in search for arg %d...\n", argno); } #endif /* PIKE_DEBUG */
aab8411999-12-07Henrik Grubbström (Grubba)  while (arg->parent && (!CDR(arg->parent) || (CDR(arg->parent) == arg))) { arg = arg->parent; } if (!arg->parent) { /* No more args. */ break; } arg = arg->parent; CDR(arg)->parent = arg; arg = CDR(arg); continue; } if (arg->token == F_PUSH_ARRAY) { /* FIXME: Should get the type from the pushed array. */ /* FIXME: Should probably be fixed in las.c:fix_type_field() */
babd872001-02-23Henrik Grubbström (Grubba)  /* FIXME: */
8a2a522001-03-03Henrik Grubbström (Grubba)  MAKE_CONSTANT_TYPE(new_type, tMap(tMixed, tMixed));
aab8411999-12-07Henrik Grubbström (Grubba)  goto set_type; }
f01a891999-12-08Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG if (l_flag > 4) { fprintf(stderr, "Found arg #%d:\n", argno); print_tree(arg); simple_describe_type(arg->type);
aab8411999-12-07Henrik Grubbström (Grubba)  }
f01a891999-12-08Henrik Grubbström (Grubba) #endif /* PIKE_DEBUG */ do { if (types[argno]) {
ac04552001-02-20Henrik Grubbström (Grubba)  struct pike_type *t = or_pike_types(types[argno], arg->type, 0);
d68a072001-02-20Henrik Grubbström (Grubba)  free_type(types[argno]);
f01a891999-12-08Henrik Grubbström (Grubba)  types[argno] = t; #ifdef PIKE_DEBUG if (l_flag > 4) { fprintf(stderr, "Resulting type for arg #%d:\n", argno); simple_describe_type(types[argno]); } #endif /* PIKE_DEBUG */ } else {
be6fec2001-04-01Henrik Grubbström (Grubba)  copy_pike_type(types[argno], arg->type);
f01a891999-12-08Henrik Grubbström (Grubba)  } argno = !argno; /* Handle the special case where CAR & CDR are the same. * Only occurrs with SHARED_NODES. */ } while (argno && arg->parent && CAR(arg->parent) == CDR(arg->parent));
aab8411999-12-07Henrik Grubbström (Grubba)  goto retrace; } if (argno) { yyerror("Odd number of arguments to aggregate_mapping()."); goto done; } if (!types[0]) {
8a2a522001-03-03Henrik Grubbström (Grubba)  MAKE_CONSTANT_TYPE(new_type, tMap(tZero, tZero));
aab8411999-12-07Henrik Grubbström (Grubba)  goto set_type; } type_stack_mark();
d68a072001-02-20Henrik Grubbström (Grubba)  push_finished_type(types[1]); push_finished_type(types[0]);
aab8411999-12-07Henrik Grubbström (Grubba)  push_type(T_MAPPING); new_type = pop_unfinished_type(); } else {
8a2a522001-03-03Henrik Grubbström (Grubba)  MAKE_CONSTANT_TYPE(new_type, tMap(tZero, tZero));
aab8411999-12-07Henrik Grubbström (Grubba)  goto set_type; } if (new_type) { set_type:
d68a072001-02-20Henrik Grubbström (Grubba)  free_type(n->type);
aab8411999-12-07Henrik Grubbström (Grubba)  n->type = new_type; #ifdef PIKE_DEBUG if (l_flag > 2) { fprintf(stderr, "Result type: "); simple_describe_type(new_type); } #endif /* PIKE_DEBUG */ if (n->parent) { n->parent->node_info |= OPT_TYPE_NOT_FIXED; } } done: if (args) { /* Not really needed, but... */ args->parent = n; } if (types[1]) {
d68a072001-02-20Henrik Grubbström (Grubba)  free_type(types[1]);
aab8411999-12-07Henrik Grubbström (Grubba)  } if (types[0]) {
d68a072001-02-20Henrik Grubbström (Grubba)  free_type(types[0]);
aab8411999-12-07Henrik Grubbström (Grubba)  } return NULL; }
937c462001-02-06Henrik Grubbström (Grubba) /*! @decl array values(string|array|mapping|multiset|object x)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
b2acc92004-05-13Martin Nilsson  *! Return an array of all possible values from indexing the value *! @[x].
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
b2acc92004-05-13Martin Nilsson  *! For strings an array of int with the ISO10646 codes of the *! characters in the string is returned.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
b2acc92004-05-13Martin Nilsson  *! For a multiset an array filled with ones (@expr{1@}) is *! returned.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! For arrays a single-level copy of @[x] is returned.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! For mappings the array may contain any value.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
b2acc92004-05-13Martin Nilsson  *! For objects which define @[lfun::_values()] that return value *! will be used.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
b2acc92004-05-13Martin Nilsson  *! For other objects an array with the values of all non-static *! symbols will be returned.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[indices()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_values(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
93b7202000-08-14Henrik Grubbström (Grubba)  ptrdiff_t size;
cb787a2000-08-24Henrik Grubbström (Grubba)  struct array *a = NULL;
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(args < 1)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_TOO_FEW_ARGS_ERROR("values", 1);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  switch(Pike_sp[-args].type)
5267b71995-08-09Fredrik Hübinette (Hubbe)  { case T_STRING:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  size = Pike_sp[-args].u.string->len;
c628dc1998-10-10Henrik Grubbström (Grubba)  a = allocate_array_no_init(size,0); while(--size >= 0)
99946c1996-02-17Fredrik Hübinette (Hubbe)  {
2523ce2003-04-28Martin Stjernholm  /* Elements are already integers. */
edf4d02000-07-06Fredrik Hübinette (Hubbe)  ITEM(a)[size].u.integer = index_shared_string(Pike_sp[-args].u.string, size);
99946c1996-02-17Fredrik Hübinette (Hubbe)  }
2523ce2003-04-28Martin Stjernholm  a->type_field = BIT_INT;
5267b71995-08-09Fredrik Hübinette (Hubbe)  break; case T_ARRAY:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  a=copy_array(Pike_sp[-args].u.array);
5267b71995-08-09Fredrik Hübinette (Hubbe)  break; case T_MAPPING:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  a=mapping_values(Pike_sp[-args].u.mapping);
5267b71995-08-09Fredrik Hübinette (Hubbe)  break;
06983f1996-09-22Fredrik Hübinette (Hubbe)  case T_MULTISET:
5b15bb2001-12-10Martin Stjernholm  a = multiset_values (Pike_sp[-args].u.multiset);
5267b71995-08-09Fredrik Hübinette (Hubbe)  break;
6d4c4c1995-11-06Fredrik Hübinette (Hubbe)  case T_OBJECT:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  a=object_values(Pike_sp[-args].u.object);
6d4c4c1995-11-06Fredrik Hübinette (Hubbe)  break;
fa31451998-05-25Henrik Grubbström (Grubba)  case T_PROGRAM:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  a = program_values(Pike_sp[-args].u.program);
fa31451998-05-25Henrik Grubbström (Grubba)  break;
0ceb871998-06-07Henrik Grubbström (Grubba)  case T_FUNCTION: {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  struct program *p = program_from_svalue(Pike_sp - args);
0ceb871998-06-07Henrik Grubbström (Grubba)  if (p) { a = program_values(p); break; } } /* FALL THROUGH */
5267b71995-08-09Fredrik Hübinette (Hubbe)  default:
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("values", 1, "string|array|mapping|multiset|" "object|program|function");
5267b71995-08-09Fredrik Hübinette (Hubbe)  return; /* make apcc happy */ } pop_n_elems(args); push_array(a); }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl object next_object(object o) *! @decl object next_object() *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Returns the next object from the list of all objects.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! All objects are stored in a linked list. *! *! @returns *! If no arguments have been given @[next_object()] will return the first *! object from the list.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! If @[o] has been specified the object after @[o] on the list will be *! returned.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @note
554e222001-05-06Henrik Grubbström (Grubba)  *! This function is not recomended to use.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[destruct()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_next_object(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) { struct object *o;
615b3e2003-01-28Martin Stjernholm 
8111162003-09-07Martin Nilsson  ASSERT_SECURITY_ROOT("next_object");
615b3e2003-01-28Martin Stjernholm 
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(args < 1) {
87a6082000-09-30Henrik Grubbström (Grubba)  o = first_object;
5267b71995-08-09Fredrik Hübinette (Hubbe)  }else{
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[-args].type != T_OBJECT)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("next_object", 1, "object");
87a6082000-09-30Henrik Grubbström (Grubba)  o = Pike_sp[-args].u.object->next;
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
87a6082000-09-30Henrik Grubbström (Grubba)  while(o && !o->prog) o=o->next;
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args); if(!o) { push_int(0); }else{
0e88611998-04-16Fredrik Hübinette (Hubbe)  ref_push_object(o);
5267b71995-08-09Fredrik Hübinette (Hubbe)  } }
fd25e02003-04-27Martin Nilsson /*! @decl program|function object_program(mixed o)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
fd25e02003-04-27Martin Nilsson  *! Return the program from which @[o] was instantiated. If the
f3f0e82003-04-27Henrik Grubbström (Grubba)  *! object was instantiated from a class using parent references *! the generating function will be returned.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
cbe8c92003-04-07Martin Nilsson  *! If @[o] is not an object or has been destructed @expr{0@} (zero)
554e222001-05-06Henrik Grubbström (Grubba)  *! will be returned.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_object_program(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) { if(args < 1)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_TOO_FEW_ARGS_ERROR("object_program", 1);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[-args].type == T_OBJECT)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  struct object *o=Pike_sp[-args].u.object;
c07fe52003-01-16Martin Stjernholm  struct program *p = o->prog; #if 0 /* This'd be nice, but it doesn't work well since the returned * function can't double as a program (program_from_svalue returns * NULL for it). */ if (p == pike_trampoline_program) { struct pike_trampoline *t = (struct pike_trampoline *) o->storage; if (t->frame && t->frame->current_object) { add_ref (o = t->frame->current_object); pop_n_elems (args); push_function (o, t->func); return; } } #endif if(p)
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  {
f3c7152001-04-14Fredrik Hübinette (Hubbe)  if((p->flags & PROGRAM_USES_PARENT) && PARENT_INFO(o)->parent && PARENT_INFO(o)->parent->prog)
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  {
f3c7152001-04-14Fredrik Hübinette (Hubbe)  INT32 id=PARENT_INFO(o)->parent_identifier; o=PARENT_INFO(o)->parent;
0e88611998-04-16Fredrik Hübinette (Hubbe)  add_ref(o);
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  pop_n_elems(args);
c07fe52003-01-16Martin Stjernholm  push_function(o, id);
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  return; }else{
0e88611998-04-16Fredrik Hübinette (Hubbe)  add_ref(p);
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_program(p); return; } }
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_int(0);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
70c9261999-12-22Henrik Grubbström (Grubba) node *fix_object_program_type(node *n) { /* Fix the type for a common case: * * object_program(object(is|implements foo)) */ node *nn;
ac04552001-02-20Henrik Grubbström (Grubba)  struct pike_type *new_type = NULL;
70c9261999-12-22Henrik Grubbström (Grubba)  if (!n->type) {
be6fec2001-04-01Henrik Grubbström (Grubba)  copy_pike_type(n->type, program_type_string);
70c9261999-12-22Henrik Grubbström (Grubba)  } if (!(nn = CDR(n))) return NULL; if ((nn->token == F_ARG_LIST) && (!(nn = CAR(nn)))) return NULL; if (!nn->type) return NULL; /* Perform the actual conversion. */ new_type = object_type_to_program_type(nn->type); if (new_type) {
d68a072001-02-20Henrik Grubbström (Grubba)  free_type(n->type);
70c9261999-12-22Henrik Grubbström (Grubba)  n->type = new_type; } return NULL; }
ed1cc32001-01-09Henrik Grubbström (Grubba) /*! @decl string reverse(string s) *! @decl array reverse(array a) *! @decl int reverse(int i) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Reverses a string, array or int.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function reverses a string, char by char, an array, value
5b916d2002-09-29Martin Stjernholm  *! by value or an int, bit by bit and returns the result. It's not *! destructive on the input value.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Reversing strings can be particularly useful for parsing difficult *! syntaxes which require scanning backwards.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[sscanf()]
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_reverse(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) { if(args < 1)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_TOO_FEW_ARGS_ERROR("reverse", 1);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  switch(Pike_sp[-args].type)
5267b71995-08-09Fredrik Hübinette (Hubbe)  { case T_STRING: { INT32 e;
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *s;
edf4d02000-07-06Fredrik Hübinette (Hubbe)  s=begin_wide_shared_string(Pike_sp[-args].u.string->len,
ac04552001-02-20Henrik Grubbström (Grubba)  Pike_sp[-args].u.string->size_shift);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  switch(Pike_sp[-args].u.string->size_shift)
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  { case 0:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  for(e=0;e<Pike_sp[-args].u.string->len;e++) STR0(s)[e]=STR0(Pike_sp[-args].u.string)[Pike_sp[-args].u.string->len-1-e];
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  break; case 1:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  for(e=0;e<Pike_sp[-args].u.string->len;e++) STR1(s)[e]=STR1(Pike_sp[-args].u.string)[Pike_sp[-args].u.string->len-1-e];
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  break; case 2:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  for(e=0;e<Pike_sp[-args].u.string->len;e++) STR2(s)[e]=STR2(Pike_sp[-args].u.string)[Pike_sp[-args].u.string->len-1-e];
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  break; } s=low_end_shared_string(s);
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_string(s); break; } case T_INT: { INT32 e;
edf4d02000-07-06Fredrik Hübinette (Hubbe)  e=Pike_sp[-args].u.integer;
5c8e891995-10-29Fredrik Hübinette (Hubbe)  e=((e & 0x55555555UL)<<1) + ((e & 0xaaaaaaaaUL)>>1); e=((e & 0x33333333UL)<<2) + ((e & 0xccccccccUL)>>2); e=((e & 0x0f0f0f0fUL)<<4) + ((e & 0xf0f0f0f0UL)>>4); e=((e & 0x00ff00ffUL)<<8) + ((e & 0xff00ff00UL)>>8); e=((e & 0x0000ffffUL)<<16)+ ((e & 0xffff0000UL)>>16);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  Pike_sp[-args].u.integer=e;
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args-1); break; }
a63b362003-11-07Martin Stjernholm  /* FIXME: Bignum support. */
5267b71995-08-09Fredrik Hübinette (Hubbe)  case T_ARRAY: { struct array *a;
edf4d02000-07-06Fredrik Hübinette (Hubbe)  a=reverse_array(Pike_sp[-args].u.array);
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_array(a); break; } default:
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("reverse", 1, "string|int|array");
5267b71995-08-09Fredrik Hübinette (Hubbe)  } } struct tupel {
7e97c31999-01-21Fredrik Hübinette (Hubbe)  int prefix; struct pike_string *ind; struct pike_string *val;
5267b71995-08-09Fredrik Hübinette (Hubbe) };
7e97c31999-01-21Fredrik Hübinette (Hubbe) /* Magic, magic and more magic */ static int find_longest_prefix(char *str,
93b7202000-08-14Henrik Grubbström (Grubba)  ptrdiff_t len,
7e97c31999-01-21Fredrik Hübinette (Hubbe)  int size_shift, struct tupel *v, INT32 a, INT32 b) {
93b7202000-08-14Henrik Grubbström (Grubba)  INT32 c,match=-1; ptrdiff_t tmp;
0fe6702004-04-30Martin Stjernholm  check_c_stack(2048);
7e97c31999-01-21Fredrik Hübinette (Hubbe)  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; }
70da5a2001-06-27Henrik Grubbström (Grubba) static int replace_sortfun(struct tupel *a,struct tupel *b) { return DO_NOT_WARN((int)my_quick_strcmp(a->ind, b->ind)); }
0fe6702004-04-30Martin Stjernholm struct replace_many_context { struct string_builder ret; struct tupel *v; }; static void free_replace_many_context (struct replace_many_context *ctx) { free_string_builder (&ctx->ret); free ((char *) ctx->v); }
70da5a2001-06-27Henrik Grubbström (Grubba) static struct pike_string *replace_many(struct pike_string *str,
3beb891996-06-21Fredrik Hübinette (Hubbe)  struct array *from, struct array *to)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
93b7202000-08-14Henrik Grubbström (Grubba)  INT32 e,num; ptrdiff_t s, length;
0fe6702004-04-30Martin Stjernholm  struct replace_many_context ctx; ONERROR uwp;
5267b71995-08-09Fredrik Hübinette (Hubbe)  int set_start[256]; int set_end[256]; if(from->size != to->size)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Replace must have equal-sized from and to arrays.\n");
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(!from->size) { reference_shared_string(str); return str; }
2575242004-05-14Martin Nilsson  if( (from->type_field & ~BIT_STRING) && (array_fix_type_field(from) & ~BIT_STRING) ) Pike_error("replace: from array not array(string).\n");
a8cdf92004-04-29Martin Nilsson 
2575242004-05-14Martin Nilsson  if( (to->type_field & ~BIT_STRING) && (array_fix_type_field(to) & ~BIT_STRING) ) Pike_error("replace: to array not array(string).\n");
a8cdf92004-04-29Martin Nilsson 
0fe6702004-04-30Martin Stjernholm  ctx.v=(struct tupel *)xalloc(sizeof(struct tupel)*from->size); init_string_builder(&ctx.ret,str->size_shift); SET_ONERROR (uwp, free_replace_many_context, &ctx);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
3e625c1998-10-11Fredrik Hübinette (Hubbe)  for(num=e=0;e<from->size;e++)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
3e625c1998-10-11Fredrik Hübinette (Hubbe)  if(ITEM(from)[e].u.string->size_shift > str->size_shift) continue;
0fe6702004-04-30Martin Stjernholm  ctx.v[num].ind=ITEM(from)[e].u.string; ctx.v[num].val=ITEM(to)[e].u.string; ctx.v[num].prefix=-2; /* Uninitialized */
3e625c1998-10-11Fredrik Hübinette (Hubbe)  num++;
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
0fe6702004-04-30Martin Stjernholm  fsort((char *)ctx.v,num,sizeof(struct tupel),(fsortfun)replace_sortfun);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
4875652004-04-29Martin Nilsson  MEMSET(set_start, 0, sizeof(set_start)); MEMSET(set_end, 0, sizeof(set_end));
5267b71995-08-09Fredrik Hübinette (Hubbe) 
3e625c1998-10-11Fredrik Hübinette (Hubbe)  for(e=0;e<num;e++)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
3e625c1998-10-11Fredrik Hübinette (Hubbe)  INT32 x;
0fe6702004-04-30Martin Stjernholm  x=index_shared_string(ctx.v[num-1-e].ind,0);
4875652004-04-29Martin Nilsson  if((x<(INT32)NELEM(set_start)) && (x >= 0))
70da5a2001-06-27Henrik Grubbström (Grubba)  set_start[x]=num-e-1;
0fe6702004-04-30Martin Stjernholm  x=index_shared_string(ctx.v[e].ind,0);
4875652004-04-29Martin Nilsson  if((x<(INT32)NELEM(set_end)) && (x >= 0))
70da5a2001-06-27Henrik Grubbström (Grubba)  set_end[x]=e+1;
5267b71995-08-09Fredrik Hübinette (Hubbe)  } length=str->len;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  for(s=0;length > 0;)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
93b7202000-08-14Henrik Grubbström (Grubba)  INT32 a,b; ptrdiff_t ch;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  ch=index_shared_string(str,s);
4875652004-04-29Martin Nilsson  if((ch<(ptrdiff_t)NELEM(set_end)) && (ch >= 0))
70da5a2001-06-27Henrik Grubbström (Grubba)  b=set_end[ch]; else b=num;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  if(b)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
4875652004-04-29Martin Nilsson  if((ch<(ptrdiff_t)NELEM(set_start)) && (ch >= 0))
70da5a2001-06-27Henrik Grubbström (Grubba)  a=set_start[ch]; else a=0;
3e625c1998-10-11Fredrik Hübinette (Hubbe) 
7e97c31999-01-21Fredrik Hübinette (Hubbe)  a=find_longest_prefix(str->str+(s << str->size_shift), length, str->size_shift,
0fe6702004-04-30Martin Stjernholm  ctx.v, a, b);
7e97c31999-01-21Fredrik Hübinette (Hubbe)  if(a!=-1)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
0fe6702004-04-30Martin Stjernholm  ch = ctx.v[a].ind->len;
7e97c31999-01-21Fredrik Hübinette (Hubbe)  if(!ch) ch=1; s+=ch; length-=ch;
0fe6702004-04-30Martin Stjernholm  string_builder_shared_strcat(&ctx.ret,ctx.v[a].val);
5267b71995-08-09Fredrik Hübinette (Hubbe)  continue; } }
0fe6702004-04-30Martin Stjernholm  string_builder_putchar(&ctx.ret,
93b7202000-08-14Henrik Grubbström (Grubba)  DO_NOT_WARN((INT32)ch));
5267b71995-08-09Fredrik Hübinette (Hubbe)  s++; length--; }
0fe6702004-04-30Martin Stjernholm  UNSET_ONERROR (uwp); free((char *)ctx.v); return finish_string_builder(&ctx.ret);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
ed1cc32001-01-09Henrik Grubbström (Grubba) /*! @decl string replace(string s, string from, string to) *! @decl string replace(string s, array(string) from, array(string) to)
bd33e72001-02-07Martin Nilsson  *! @decl string replace(string s, mapping(string:string) replacements)
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! @decl array replace(array a, mixed from, mixed to) *! @decl mapping replace(mapping a, mixed from, mixed to) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Generic replace function.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function can do several kinds replacement operations, the *! different syntaxes do different things as follows:
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! If all the arguments are strings, a copy of @[s] with every *! occurrence of @[from] replaced with @[to] will be returned. *! Special case: @[to] will be inserted between every character in *! @[s] if @[from] is the empty string.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! If the first argument is a string, and the others array(string), a string *! with every occurrance of @[from][@i{i@}] in @[s] replaced with *! @[to][@i{i@}] will be returned. Instead of the arrays @[from] and @[to]
f79bd82003-04-01Martin Nilsson  *! a mapping equvivalent to @expr{@[mkmapping](@[from], @[to])@} can be
554e222001-05-06Henrik Grubbström (Grubba)  *! used.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! If the first argument is an array or mapping, the values of @[a] which *! are @[`==()] with @[from] will be replaced with @[to] destructively. *! @[a] will then be returned.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @note
554e222001-05-06Henrik Grubbström (Grubba)  *! Note that @[replace()] on arrays and mappings is a destructive operation.
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_replace(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) { if(args < 3)
f7a4462000-10-31Mirar (Pontus Hagland)  { if (args==2 &&
a8cdf92004-04-29Martin Nilsson  Pike_sp[-1].type==T_MAPPING)
f7a4462000-10-31Mirar (Pontus Hagland)  {
200bfd2004-05-14Martin Nilsson  struct mapping *m = Pike_sp[-1].u.mapping; if( (m->data->ind_types & ~BIT_STRING) || (m->data->val_types & ~BIT_STRING) ) { mapping_fix_type_field(Pike_sp[-1].u.mapping); if( (m->data->ind_types & ~BIT_STRING) || (m->data->val_types & ~BIT_STRING) ) { SIMPLE_BAD_ARG_ERROR("replace", 2, "mapping(string:string)"); } }
f7a4462000-10-31Mirar (Pontus Hagland)  stack_dup(); f_indices(1); stack_swap(); f_values(1); args++; } else SIMPLE_TOO_FEW_ARGS_ERROR("replace", 3); }
5267b71995-08-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  switch(Pike_sp[-args].type)
5267b71995-08-09Fredrik Hübinette (Hubbe)  { case T_ARRAY: {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  array_replace(Pike_sp[-args].u.array,Pike_sp+1-args,Pike_sp+2-args);
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args-1); break; } case T_MAPPING: {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  mapping_replace(Pike_sp[-args].u.mapping,Pike_sp+1-args,Pike_sp+2-args);
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args-1); break; } case T_STRING: {
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *s;
edf4d02000-07-06Fredrik Hübinette (Hubbe)  switch(Pike_sp[1-args].type)
5267b71995-08-09Fredrik Hübinette (Hubbe)  { default:
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("replace", 2, "string|array");
a8cdf92004-04-29Martin Nilsson 
5267b71995-08-09Fredrik Hübinette (Hubbe)  case T_STRING:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[2-args].type != T_STRING)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("replace", 3, "string");
5267b71995-08-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  s=string_replace(Pike_sp[-args].u.string, Pike_sp[1-args].u.string, Pike_sp[2-args].u.string);
5267b71995-08-09Fredrik Hübinette (Hubbe)  break; case T_ARRAY:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[2-args].type != T_ARRAY)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("replace", 3, "array");
5267b71995-08-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  s=replace_many(Pike_sp[-args].u.string, Pike_sp[1-args].u.array, Pike_sp[2-args].u.array);
5267b71995-08-09Fredrik Hübinette (Hubbe)  } pop_n_elems(args); push_string(s); break; }
8b63781996-04-11Fredrik Hübinette (Hubbe)  default:
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("replace", 1, "array|mapping|string");
5267b71995-08-09Fredrik Hübinette (Hubbe)  } }
6377672001-06-01Henrik Grubbström (Grubba) node *optimize_replace(node *n) { node **arg0 = my_get_arg(&_CDR(n), 0); struct pike_type *array_zero; struct pike_type *mapping_zero; MAKE_CONSTANT_TYPE(array_zero, tArr(tZero)); MAKE_CONSTANT_TYPE(mapping_zero, tMap(tZero, tZero)); if (arg0 && (pike_types_le(array_zero, (*arg0)->type) || pike_types_le(mapping_zero, (*arg0)->type))) { /* First argument might be an array or a mapping. * * replace() is destructive on arrays and mappings. */ n->node_info |= OPT_SIDE_EFFECT; n->tree_info |= OPT_SIDE_EFFECT;
fed7de2001-06-28Henrik Grubbström (Grubba)  } else { /* First argument is not an array or mapping, * * It thus must be a string. */ node **arg1 = my_get_arg(&_CDR(n), 1); node **arg2 = my_get_arg(&_CDR(n), 2); if (arg1 && pike_types_le((*arg1)->type, array_type_string) && arg2 && pike_types_le((*arg2)->type, array_type_string)) { /* The second and third arguments are arrays. */ if (!is_const(*arg0) && is_const(*arg1) && is_const(*arg2)) { /* The second and third arguments are constants. */ struct svalue *save_sp = Pike_sp; JMP_BUF tmp; if (SETJMP(tmp)) { yywarning("Optimizer failure in replace()."); pop_n_elems(Pike_sp - save_sp);
c1b8f02001-07-02Martin Stjernholm  free_svalue(&throw_value); throw_value.type = T_INT;
fed7de2001-06-28Henrik Grubbström (Grubba)  } else { extern struct program *multi_string_replace_program; INT16 lfun;
cbd1f22001-06-29Henrik Grubbström (Grubba)  struct object *replace_obj;
fed7de2001-06-28Henrik Grubbström (Grubba)  node *ret = NULL;
9f85c32002-10-25Marcus Comstedt  INT32 args = eval_low(*arg1,1); /* NOTE: Addition splitted to ensure */ args += eval_low(*arg2,1); /* correct evaluation order. */
cbd1f22001-06-29Henrik Grubbström (Grubba)  replace_obj = clone_object(multi_string_replace_program, args);
fed7de2001-06-28Henrik Grubbström (Grubba)  push_object(replace_obj); if (replace_obj->prog && ((lfun = FIND_LFUN(replace_obj->prog, LFUN_CALL)) != -1)) { Pike_sp[-1].subtype = lfun; Pike_sp[-1].type = PIKE_T_FUNCTION; ADD_NODE_REF2(*arg0, ret = mkapplynode(mkconstantsvaluenode(Pike_sp-1), *arg0); ); UNSETJMP(tmp);
620f8e2001-06-28Fredrik Hübinette (Hubbe)  pop_n_elems(Pike_sp - save_sp);
fed7de2001-06-28Henrik Grubbström (Grubba)  free_type(array_zero); free_type(mapping_zero); return ret; } } UNSETJMP(tmp);
620f8e2001-06-28Fredrik Hübinette (Hubbe)  pop_n_elems(Pike_sp - save_sp);
fed7de2001-06-28Henrik Grubbström (Grubba)  } }
6377672001-06-01Henrik Grubbström (Grubba)  }
84bf7e2001-06-05Martin Stjernholm  free_type(array_zero); free_type(mapping_zero);
6377672001-06-01Henrik Grubbström (Grubba)  return NULL; }
937c462001-02-06Henrik Grubbström (Grubba) /*! @decl program compile(string source, object|void handler, @
dc9ca62001-12-12Martin Nilsson  *! int|void major, int|void minor,@ *! program|void target, object|void placeholder)
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Compile a string to a program.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function takes a piece of Pike code as a string and *! compiles it into a clonable program.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! The optional argument @[handler] is used to specify an alternative *! error handler. If it is not specified the current master object will *! be used.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! The optional arguments @[major] and @[minor] are used to tell the *! compiler to attempt to be compatible with Pike @[major].@[minor].
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @note
554e222001-05-06Henrik Grubbström (Grubba)  *! Note that @[source] must contain the complete source for a program. *! It is not possible to compile a single expression or statement.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Also note that @[compile()] does not preprocess the program. *! To preprocess the program you can use @[compile_string()] or *! call the preprocessor manually by calling @[cpp()].
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[compile_string()], @[compile_file()], @[cpp()], @[master()]
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_compile(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
aa68b12001-03-19Fredrik Hübinette (Hubbe)  struct program *p=0;
ac87152000-09-25Fredrik Hübinette (Hubbe)  struct object *o;
aa68b12001-03-19Fredrik Hübinette (Hubbe)  struct object *placeholder=0;
ac87152000-09-25Fredrik Hübinette (Hubbe)  int major=-1; int minor=-1;
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) 
5267b71995-08-09Fredrik Hübinette (Hubbe) 
ac87152000-09-25Fredrik Hübinette (Hubbe)  check_all_args("compile",args, BIT_STRING, BIT_VOID | BIT_INT | BIT_OBJECT, BIT_VOID | BIT_INT, BIT_VOID | BIT_INT,
aa68b12001-03-19Fredrik Hübinette (Hubbe)  BIT_VOID | BIT_INT | BIT_PROGRAM, BIT_VOID | BIT_INT | BIT_OBJECT,
ac87152000-09-25Fredrik Hübinette (Hubbe)  0);
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) 
18ab182001-08-15Fredrik Hübinette (Hubbe)  check_c_stack(65536);
ac87152000-09-25Fredrik Hübinette (Hubbe)  o=0;
aa68b12001-03-19Fredrik Hübinette (Hubbe)  switch(args) { case 3: SIMPLE_BAD_ARG_ERROR("compile", 4, "int"); default: if(Pike_sp[5-args].type == T_OBJECT) placeholder=Pike_sp[5-args].u.object;
42a92c1999-11-04Henrik Grubbström (Grubba) 
aa68b12001-03-19Fredrik Hübinette (Hubbe)  case 5: if(Pike_sp[4-args].type == T_PROGRAM) p=Pike_sp[4-args].u.program;
ac87152000-09-25Fredrik Hübinette (Hubbe) 
aa68b12001-03-19Fredrik Hübinette (Hubbe)  case 4:
9b150a2002-05-11Martin Nilsson  major=Pike_sp[2-args].u.integer; minor=Pike_sp[3-args].u.integer;
aa68b12001-03-19Fredrik Hübinette (Hubbe)  case 2: if(Pike_sp[1-args].type == T_OBJECT) o=Pike_sp[1-args].u.object; case 0: case 1: break;
42a92c1999-11-04Henrik Grubbström (Grubba)  }
ac87152000-09-25Fredrik Hübinette (Hubbe) 
aa68b12001-03-19Fredrik Hübinette (Hubbe)  p = compile(Pike_sp[-args].u.string, o, major, minor, p, placeholder);
ac87152000-09-25Fredrik Hübinette (Hubbe) 
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_program(p); }
ed1cc32001-01-09Henrik Grubbström (Grubba) 
937c462001-02-06Henrik Grubbström (Grubba) /*! @decl array|mapping|multiset set_weak_flag(array|mapping|multiset m, @
84bf7e2001-06-05Martin Stjernholm  *! int state) *! *! Set the value @[m] to use weak or normal references in its *! indices and/or values (whatever is applicable). @[state] is a
cbe8c92003-04-07Martin Nilsson  *! bitfield built by using @expr{|@} between the following flags:
84bf7e2001-06-05Martin Stjernholm  *!
b00d6d2001-07-27Martin Nilsson  *! @int *! @value Pike.WEAK_INDICES
84bf7e2001-06-05Martin Stjernholm  *! Use weak references for indices. Only applicable for *! multisets and mappings.
b00d6d2001-07-27Martin Nilsson  *! @value Pike.WEAK_VALUES
84bf7e2001-06-05Martin Stjernholm  *! Use weak references for values. Only applicable for arrays *! and mappings.
b00d6d2001-07-27Martin Nilsson  *! @value Pike.WEAK
cbe8c92003-04-07Martin Nilsson  *! Shorthand for @expr{Pike.WEAK_INDICES|Pike.WEAK_VALUES@}.
b00d6d2001-07-27Martin Nilsson  *! @endint
84bf7e2001-06-05Martin Stjernholm  *! *! If a flag is absent, the corresponding field will use normal
cbe8c92003-04-07Martin Nilsson  *! references. @[state] can also be @expr{1@} as a compatibility
84bf7e2001-06-05Martin Stjernholm  *! measure; it's treated like @[Pike.WEAK].
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @returns
937c462001-02-06Henrik Grubbström (Grubba)  *! @[m] will be returned.
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
5f06241999-04-11Fredrik Hübinette (Hubbe) #define SETFLAG(FLAGS,FLAG,ONOFF) \ FLAGS = (FLAGS & ~FLAG) | ( ONOFF ? FLAG : 0 )
3b589f1999-02-04Fredrik Hübinette (Hubbe) void f_set_weak_flag(INT32 args) {
5f06241999-04-11Fredrik Hübinette (Hubbe)  struct svalue *s;
5665ab1999-07-28Henrik Grubbström (Grubba)  INT_TYPE ret;
be08a82001-06-06Martin Stjernholm  int flags;
5665ab1999-07-28Henrik Grubbström (Grubba) 
5f06241999-04-11Fredrik Hübinette (Hubbe)  get_all_args("set_weak_flag",args,"%*%i",&s,&ret);
84bf7e2001-06-05Martin Stjernholm  if (ret == 1) ret = PIKE_WEAK_BOTH;
5f06241999-04-11Fredrik Hübinette (Hubbe)  switch(s->type)
3b589f1999-02-04Fredrik Hübinette (Hubbe)  {
5f06241999-04-11Fredrik Hübinette (Hubbe)  case T_ARRAY:
be08a82001-06-06Martin Stjernholm  flags = array_get_flags(s->u.array); SETFLAG(flags,ARRAY_WEAK_FLAG,ret & PIKE_WEAK_VALUES); s->u.array = array_set_flags(s->u.array, flags);
5f06241999-04-11Fredrik Hübinette (Hubbe)  break;
be08a82001-06-06Martin Stjernholm  case T_MAPPING: flags = mapping_get_flags(s->u.mapping);
84bf7e2001-06-05Martin Stjernholm  flags = (flags & ~PIKE_WEAK_BOTH) | (ret & PIKE_WEAK_BOTH);
880be62000-09-04Martin Stjernholm  mapping_set_flags(s->u.mapping, flags);
5f06241999-04-11Fredrik Hübinette (Hubbe)  break;
e99c7a1999-10-29Martin Stjernholm  case T_MULTISET:
5b15bb2001-12-10Martin Stjernholm  flags = multiset_get_flags (s->u.multiset); flags = (flags & ~PIKE_WEAK_BOTH) | (ret & PIKE_WEAK_BOTH); multiset_set_flags (s->u.multiset, flags);
e99c7a1999-10-29Martin Stjernholm  break;
5f06241999-04-11Fredrik Hübinette (Hubbe)  default:
e99c7a1999-10-29Martin Stjernholm  SIMPLE_BAD_ARG_ERROR("set_weak_flag",1,"array|mapping|multiset");
3b589f1999-02-04Fredrik Hübinette (Hubbe)  }
5f06241999-04-11Fredrik Hübinette (Hubbe)  pop_n_elems(args-1);
3b589f1999-02-04Fredrik Hübinette (Hubbe) }
ed1cc32001-01-09Henrik Grubbström (Grubba) /*! @decl int objectp(mixed arg) *!
cbe8c92003-04-07Martin Nilsson  *! Returns @expr{1@} if @[arg] is an object, @expr{0@} (zero) otherwise.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[mappingp()], @[programp()], @[arrayp()], @[stringp()], @[functionp()], *! @[multisetp()], @[floatp()], @[intp()]
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_objectp(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
d0d01b1999-03-20Henrik Grubbström (Grubba)  if(args<1) SIMPLE_TOO_FEW_ARGS_ERROR("objectp", 1);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[-args].type != T_OBJECT || !Pike_sp[-args].u.object->prog
3905cf1999-11-11Fredrik Hübinette (Hubbe) #ifdef AUTO_BIGNUM
edf4d02000-07-06Fredrik Hübinette (Hubbe)  || is_bignum_object(Pike_sp[-args].u.object)
3905cf1999-11-11Fredrik Hübinette (Hubbe) #endif )
5267b71995-08-09Fredrik Hübinette (Hubbe)  { pop_n_elems(args); push_int(0); }else{ pop_n_elems(args); push_int(1); } }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl int functionp(mixed arg) *!
cbe8c92003-04-07Martin Nilsson  *! Returns @expr{1@} if @[arg] is a function, @expr{0@} (zero) otherwise.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[mappingp()], @[programp()], @[arrayp()], @[stringp()], @[objectp()], *! @[multisetp()], @[floatp()], @[intp()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_functionp(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
2e04432001-04-09Per Hedbor  int res = 0;
d0d01b1999-03-20Henrik Grubbström (Grubba)  if(args<1) SIMPLE_TOO_FEW_ARGS_ERROR("functionp", 1);
2e04432001-04-09Per Hedbor  if( Pike_sp[-args].type == T_FUNCTION &&
afbf0a2001-04-09Fredrik Hübinette (Hubbe)  (Pike_sp[-args].subtype == FUNCTION_BUILTIN || Pike_sp[-args].u.object->prog))
2e04432001-04-09Per Hedbor  res=1; pop_n_elems(args); push_int(res); } /*! @decl int callablep(mixed arg) *!
cbe8c92003-04-07Martin Nilsson  *! Returns @expr{1@} if @[arg] is a callable, @expr{0@} (zero) otherwise.
2e04432001-04-09Per Hedbor  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[mappingp()], @[programp()], @[arrayp()], @[stringp()], @[objectp()], *! @[multisetp()], @[floatp()], @[intp()]
2e04432001-04-09Per Hedbor  */ PMOD_EXPORT void f_callablep(INT32 args) { int res = 0; if(args<1) SIMPLE_TOO_FEW_ARGS_ERROR("callablep", 1); switch( Pike_sp[-args].type )
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
2e04432001-04-09Per Hedbor  case T_FUNCTION: if( Pike_sp[-args].subtype != FUNCTION_BUILTIN && !Pike_sp[-args].u.object->prog) break; res = 1; break; case T_PROGRAM: res = 1; break; case T_OBJECT: if( Pike_sp[-args].u.object->prog && FIND_LFUN( Pike_sp[-args].u.object->prog, LFUN_CALL ) != -1 ) res = 1;
e8a76d2003-10-30Martin Nilsson  break; case T_ARRAY:
a8cdf92004-04-29Martin Nilsson  array_fix_type_field(Pike_sp[-args].u.array); if( (Pike_sp[-args].u.array->type_field==BIT_CALLABLE) || !Pike_sp[-args].u.array->type_field) {
e8a76d2003-10-30Martin Nilsson  res = 1;
a8cdf92004-04-29Martin Nilsson  } else if( !(Pike_sp[-args].u.array->type_field & ~(BIT_CALLABLE|BIT_INT)) ) { struct array *a = Pike_sp[-args].u.array; int i; res = 1; for(i=0; i<a->size; i++) if( ITEM(a)[i].type == T_INT && ITEM(a)[i].u.integer ) { res = 0; break; } }
e8a76d2003-10-30Martin Nilsson  break;
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
2e04432001-04-09Per Hedbor  pop_n_elems(args); push_int(res);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
89b0721998-05-05Fredrik Hübinette (Hubbe) #ifndef HAVE_AND_USE_POLL #undef HAVE_POLL #endif
768f532002-11-25Martin Nilsson /*! @decl void sleep(int|float s, void|int abort_on_signal)
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function makes the program stop for @[s] seconds.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
768f532002-11-25Martin Nilsson  *! Only signal handlers can interrupt the sleep, and only when *! @[abort_on_signal] is set. If more than one thread is running *! the signal must be sent to the sleeping thread. Other callbacks *! are not called during sleep.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
93af2d2003-10-31Martin Stjernholm  *! If @[s] is zero then this thread will yield to other threads but *! not sleep otherwise. Note that Pike yields internally at regular *! intervals so it's normally not necessary to do this. *!
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! @seealso
768f532002-11-25Martin Nilsson  *! @[signal()], @[delay()]
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_sleep(INT32 args)
cb22561995-10-11Fredrik Hübinette (Hubbe) {
bebcca2001-11-08Fredrik Hübinette (Hubbe) #ifdef HAVE_GETHRTIME hrtime_t t0,tv; #else struct timeval t0,tv; #endif double delay=0.0; int do_abort_on_signal; #ifdef HAVE_GETHRTIME t0=tv=gethrtime(); #define GET_TIME_ELAPSED tv=gethrtime() #define TIME_ELAPSED (tv-t0)*1e-9 #else GETTIMEOFDAY(&t0); tv=t0; #define GET_TIME_ELAPSED GETTIMEOFDAY(&tv) #define TIME_ELAPSED ((tv.tv_sec-t0.tv_sec) + (tv.tv_usec-t0.tv_usec)*1e-6) #endif #define FIX_LEFT() \ GET_TIME_ELAPSED; \ left = delay - TIME_ELAPSED; switch(Pike_sp[-args].type) { case T_INT: delay=(double)Pike_sp[-args].u.integer; break; case T_FLOAT: delay=(double)Pike_sp[-args].u.float_number; break; } /* Special case, sleep(0) means 'yield' */ if(delay == 0.0) { check_threads_etc(); pop_n_elems(args); return; }
9f516a2001-12-16Martin Stjernholm  if(args > 1 && !UNSAFE_IS_ZERO(Pike_sp + 1-args))
bebcca2001-11-08Fredrik Hübinette (Hubbe)  { do_abort_on_signal=1; }else{ do_abort_on_signal=0; } pop_n_elems(args); while(1) { double left; /* THREADS_ALLOW may take longer time then POLL_SLEEP_LIMIT */ THREADS_ALLOW(); do { FIX_LEFT(); if(left<=0.0) break; #ifdef __NT__ Sleep(DO_NOT_WARN((int)(left*1000))); #elif defined(HAVE_POLL)
782a902003-09-11Henrik Grubbström (Grubba)  { /* MacOS X is stupid, and requires a non-NULL pollfd pointer. */ struct pollfd sentinel; poll(&sentinel, 0, (int)(left*1000)); }
bebcca2001-11-08Fredrik Hübinette (Hubbe) #else { struct timeval t3; t3.tv_sec=left; t3.tv_usec=(int)((left - (int)left)*1e6); select(0,0,0,0,&t3); } #endif } while(0); THREADS_DISALLOW(); if(do_abort_on_signal) return; FIX_LEFT(); if(left<=0.0) { break; }else{
700dac2002-02-05Martin Stjernholm  check_threads_etc();
bebcca2001-11-08Fredrik Hübinette (Hubbe)  } } } #undef FIX_LEFT #undef GET_TIME_ELAPSED #undef TIME_ELAPSED /*! @decl void delay(int|float s) *! *! This function makes the program stop for @[s] seconds. *! *! Only signal handlers can interrupt the sleep. Other callbacks are
768f532002-11-25Martin Nilsson  *! not called during delay. Beware that this function uses busy-waiting
7a5abc2001-11-27Martin Stjernholm  *! to achieve the highest possible accuracy.
bebcca2001-11-08Fredrik Hübinette (Hubbe)  *! *! @seealso *! @[signal()], @[sleep()] */ PMOD_EXPORT void f_delay(INT32 args) {
8380171999-12-06Mirar (Pontus Hagland) #define POLL_SLEEP_LIMIT 0.02
cb22561995-10-11Fredrik Hübinette (Hubbe) 
8380171999-12-06Mirar (Pontus Hagland) #ifdef HAVE_GETHRTIME hrtime_t t0,tv; #else struct timeval t0,tv; #endif
3beb891996-06-21Fredrik Hübinette (Hubbe) 
8380171999-12-06Mirar (Pontus Hagland)  double delay=0.0; int do_microsleep;
f813372001-07-23Fredrik Hübinette (Hubbe)  int do_abort_on_signal;
3beb891996-06-21Fredrik Hübinette (Hubbe) 
8380171999-12-06Mirar (Pontus Hagland) #ifdef HAVE_GETHRTIME t0=tv=gethrtime(); #define GET_TIME_ELAPSED tv=gethrtime() #define TIME_ELAPSED (tv-t0)*1e-9 #else GETTIMEOFDAY(&t0); tv=t0; #define GET_TIME_ELAPSED GETTIMEOFDAY(&tv) #define TIME_ELAPSED ((tv.tv_sec-t0.tv_sec) + (tv.tv_usec-t0.tv_usec)*1e-6)
dac6371999-10-17Mirar (Pontus Hagland) #endif
3beb891996-06-21Fredrik Hübinette (Hubbe) 
0dbb5c2000-02-22Fredrik Hübinette (Hubbe) #define FIX_LEFT() \ GET_TIME_ELAPSED; \ left = delay - TIME_ELAPSED; \ if (do_microsleep) left-=POLL_SLEEP_LIMIT;
edf4d02000-07-06Fredrik Hübinette (Hubbe)  switch(Pike_sp[-args].type)
8380171999-12-06Mirar (Pontus Hagland)  { case T_INT:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  delay=(double)Pike_sp[-args].u.integer;
8380171999-12-06Mirar (Pontus Hagland)  break;
b48f281998-03-26Henrik Grubbström (Grubba) 
8380171999-12-06Mirar (Pontus Hagland)  case T_FLOAT:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  delay=(double)Pike_sp[-args].u.float_number;
8380171999-12-06Mirar (Pontus Hagland)  break; }
cb22561995-10-11Fredrik Hübinette (Hubbe) 
0dbb5c2000-02-22Fredrik Hübinette (Hubbe)  /* Special case, sleep(0) means 'yield' */ if(delay == 0.0) { check_threads_etc(); pop_n_elems(args); return; }
9f516a2001-12-16Martin Stjernholm  if(args > 1 && !UNSAFE_IS_ZERO(Pike_sp + 1-args))
f813372001-07-23Fredrik Hübinette (Hubbe)  { do_microsleep=0; do_abort_on_signal=1; }else{ do_microsleep=delay<10; do_abort_on_signal=0; }
8380171999-12-06Mirar (Pontus Hagland)  pop_n_elems(args);
f813372001-07-23Fredrik Hübinette (Hubbe)  if (delay>POLL_SLEEP_LIMIT || !do_microsleep)
2ad6b72000-01-29Mirar (Pontus Hagland)  {
0dbb5c2000-02-22Fredrik Hübinette (Hubbe)  while(1) { double left; /* THREADS_ALLOW may take longer time then POLL_SLEEP_LIMIT */ THREADS_ALLOW();
865dc22000-04-13Henrik Grubbström (Grubba)  do { FIX_LEFT(); if(left<=0.0) break;
0dbb5c2000-02-22Fredrik Hübinette (Hubbe) 
89b0721998-05-05Fredrik Hübinette (Hubbe) #ifdef __NT__
93b7202000-08-14Henrik Grubbström (Grubba)  Sleep(DO_NOT_WARN((int)(left*1000)));
89b0721998-05-05Fredrik Hübinette (Hubbe) #elif defined(HAVE_POLL)
782a902003-09-11Henrik Grubbström (Grubba)  { /* MacOS X is stupid, and requires a non-NULL pollfd pointer. */ struct pollfd sentinel; poll(&sentinel, 0, (int)(left*1000)); }
89b0721998-05-05Fredrik Hübinette (Hubbe) #else
865dc22000-04-13Henrik Grubbström (Grubba)  { struct timeval t3; t3.tv_sec=left; t3.tv_usec=(int)((left - (int)left)*1e6); select(0,0,0,0,&t3); }
89b0721998-05-05Fredrik Hübinette (Hubbe) #endif
865dc22000-04-13Henrik Grubbström (Grubba)  } while(0);
0dbb5c2000-02-22Fredrik Hübinette (Hubbe)  THREADS_DISALLOW();
f813372001-07-23Fredrik Hübinette (Hubbe)  if(do_abort_on_signal) return;
0dbb5c2000-02-22Fredrik Hübinette (Hubbe)  FIX_LEFT(); if(left<=0.0) { break; }else{
700dac2002-02-05Martin Stjernholm  check_threads_etc();
0dbb5c2000-02-22Fredrik Hübinette (Hubbe)  } }
2ad6b72000-01-29Mirar (Pontus Hagland)  }
8380171999-12-06Mirar (Pontus Hagland)  if (do_microsleep) while (delay>TIME_ELAPSED) GET_TIME_ELAPSED;
cb22561995-10-11Fredrik Hübinette (Hubbe) }
937c462001-02-06Henrik Grubbström (Grubba) /*! @decl int gc()
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Force garbage collection.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function checks all the memory for cyclic structures such *! as arrays containing themselves and frees them if appropriate.
7a5abc2001-11-27Martin Stjernholm  *! It also frees up destructed objects and things with only weak
5a0d5b2003-01-11Martin Stjernholm  *! references.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Normally there is no need to call this function since Pike will *! call it by itself every now and then. (Pike will try to predict *! when 20% of all arrays/object/programs in memory is 'garbage' *! and call this routine then.)
5a0d5b2003-01-11Martin Stjernholm  *! *! @returns *! The amount of garbage is returned. This is the number of arrays, *! mappings, multisets, objects and programs that had no nonweak *! external references during the garbage collection. It's normally *! the same as the number of freed things, but there might be some *! difference since destroy() functions are called during freeing, *! which can cause more things to be freed or allocated.
51adb82003-01-12Martin Stjernholm  *! *! @seealso *! @[Pike.gc_parameters], @[Debug.gc_status]
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
624d091996-02-24Fredrik Hübinette (Hubbe) void f_gc(INT32 args) { pop_n_elems(args);
51adb82003-01-12Martin Stjernholm  push_int(do_gc(NULL, 1));
624d091996-02-24Fredrik Hübinette (Hubbe) }
5267b71995-08-09Fredrik Hübinette (Hubbe) #ifdef TYPEP #undef TYPEP #endif
aa73fc1999-10-21Fredrik Hübinette (Hubbe)  #define TYPEP(ID,NAME,TYPE,TYPE_NAME) \
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void ID(INT32 args) \
aa73fc1999-10-21Fredrik Hübinette (Hubbe) { \ int t; \ if(args<1) \ SIMPLE_TOO_FEW_ARGS_ERROR(NAME, 1); \
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[-args].type == T_OBJECT && Pike_sp[-args].u.object->prog) \
aa73fc1999-10-21Fredrik Hübinette (Hubbe)  { \
edf4d02000-07-06Fredrik Hübinette (Hubbe)  int fun=FIND_LFUN(Pike_sp[-args].u.object->prog,LFUN__IS_TYPE); \
aa73fc1999-10-21Fredrik Hübinette (Hubbe)  if(fun != -1) \ { \ push_constant_text(TYPE_NAME); \
edf4d02000-07-06Fredrik Hübinette (Hubbe)  apply_low(Pike_sp[-args-1].u.object,fun,1); \
aa73fc1999-10-21Fredrik Hübinette (Hubbe)  stack_unlink(args); \ return; \ } \ } \
edf4d02000-07-06Fredrik Hübinette (Hubbe)  t=Pike_sp[-args].type == TYPE; \
aa73fc1999-10-21Fredrik Hübinette (Hubbe)  pop_n_elems(args); \ push_int(t); \
10f5031999-10-21Fredrik Noring }
b1f4eb1998-01-13Fredrik Hübinette (Hubbe) 
3b0f9f1999-10-22Henrik Grubbström (Grubba) 
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl int programp(mixed arg) *!
cbe8c92003-04-07Martin Nilsson  *! Returns @expr{1@} if @[arg] is a program, @expr{0@} (zero) otherwise.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[mappingp()], @[intp()], @[arrayp()], @[stringp()], @[objectp()], *! @[multisetp()], @[floatp()], @[functionp()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_programp(INT32 args)
b1f4eb1998-01-13Fredrik Hübinette (Hubbe) { if(args<1)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_TOO_FEW_ARGS_ERROR("programp", 1);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  switch(Pike_sp[-args].type)
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  { case T_PROGRAM: pop_n_elems(args); push_int(1); return; case T_FUNCTION:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(program_from_function(Pike_sp-args))
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  { pop_n_elems(args); push_int(1); return; } default: pop_n_elems(args); push_int(0); } }
9c1a7b2001-01-08Henrik Grubbström (Grubba) /*! @decl int intp(mixed arg) *!
cbe8c92003-04-07Martin Nilsson  *! Returns @expr{1@} if @[arg] is an int, @expr{0@} (zero) otherwise.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[mappingp()], @[programp()], @[arrayp()], @[stringp()], @[objectp()], *! @[multisetp()], @[floatp()], @[functionp()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */ /*! @decl int mappingp(mixed arg) *!
cbe8c92003-04-07Martin Nilsson  *! Returns @expr{1@} if @[arg] is a mapping, @expr{0@} (zero) otherwise.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[intp()], @[programp()], @[arrayp()], @[stringp()], @[objectp()], *! @[multisetp()], @[floatp()], @[functionp()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */ /*! @decl int arrayp(mixed arg) *!
cbe8c92003-04-07Martin Nilsson  *! Returns @expr{1@} if @[arg] is an array, @expr{0@} (zero) otherwise.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[intp()], @[programp()], @[mappingp()], @[stringp()], @[objectp()], *! @[multisetp()], @[floatp()], @[functionp()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */ /*! @decl int multisetp(mixed arg) *!
cbe8c92003-04-07Martin Nilsson  *! Returns @expr{1@} if @[arg] is a multiset, @expr{0@} (zero) otherwise.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[intp()], @[programp()], @[arrayp()], @[stringp()], @[objectp()], *! @[mappingp()], @[floatp()], @[functionp()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */ /*! @decl int stringp(mixed arg) *!
cbe8c92003-04-07Martin Nilsson  *! Returns @expr{1@} if @[arg] is a string, @expr{0@} (zero) otherwise.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[intp()], @[programp()], @[arrayp()], @[multisetp()], @[objectp()], *! @[mappingp()], @[floatp()], @[functionp()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */ /*! @decl int floatp(mixed arg) *!
cbe8c92003-04-07Martin Nilsson  *! Returns @expr{1@} if @[arg] is a float, @expr{0@} (zero) otherwise.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[intp()], @[programp()], @[arrayp()], @[multisetp()], @[objectp()], *! @[mappingp()], @[stringp()], @[functionp()]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
d9a93b2001-07-01Fredrik Hübinette (Hubbe) 
10f5031999-10-21Fredrik Noring TYPEP(f_intp, "intp", T_INT, "int") TYPEP(f_mappingp, "mappingp", T_MAPPING, "mapping") TYPEP(f_arrayp, "arrayp", T_ARRAY, "array") TYPEP(f_multisetp, "multisetp", T_MULTISET, "multiset") TYPEP(f_stringp, "stringp", T_STRING, "string") TYPEP(f_floatp, "floatp", T_FLOAT, "float")
ed1cc32001-01-09Henrik Grubbström (Grubba)  /*! @decl array sort(array(mixed) index, array(mixed) ... data) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Sort arrays destructively.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function sorts the array @[index] destructively. That means *! that the array itself is changed and returned, no copy is created.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! If extra arguments are given, they are supposed to be arrays of the *! same size as @[index]. Each of these arrays will be modified in the *! same way as @[index]. I.e. if index 3 is moved to position 0 in @[index] *! index 3 will be moved to position 0 in all the other arrays as well.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
0c49782003-04-27Martin Stjernholm  *! The sort order is as follows: *! *! @ul *! @item *! Integers and floats are sorted in ascending order. *! @item *! Strings are sorted primarily on the first characters that are *! different, and secondarily with shorter strings before longer. *! Different characters are sorted in ascending order on the *! character value. Thus the sort order is not locale dependent. *! @item *! Arrays are sorted recursively on the first element. Empty *! arrays are sorted before nonempty ones. *! @item *! Multisets are sorted recursively on the first index. Empty *! multisets are sorted before nonempty ones. *! @item *! Objects are sorted in ascending order according to @[`<()], *! @[`>()] and @[`==()]. *! @item *! Other types aren't reordered. *! @item *! Different types are sorted in this order: Arrays, mappings, *! multisets, objects, functions, programs, strings, types, *! integers and floats. Note however that objects can control *! their ordering wrt other types with @[`<], @[`>] and @[`==], *! so this ordering of types only applies to objects without *! those functions. *! @endul
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @returns
0c49782003-04-27Martin Stjernholm  *! The first argument is returned.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @note
0c49782003-04-27Martin Stjernholm  *! The sort is stable, i.e. elements that are compare-wise equal *! aren't reordered.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @seealso
c306092003-02-16Martin Stjernholm  *! @[Array.sort_array], @[reverse()]
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_sort(INT32 args)
ed70b71996-06-09Fredrik Hübinette (Hubbe) { INT32 e,*order;
0c49782003-04-27Martin Stjernholm  struct array *a;
ed70b71996-06-09Fredrik Hübinette (Hubbe) 
bee4301997-02-24Fredrik Hübinette (Hubbe)  if(args < 1)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_TOO_FEW_ARGS_ERROR("sort", 1);
0c49782003-04-27Martin Stjernholm  if(Pike_sp[-args].type != T_ARRAY) SIMPLE_BAD_ARG_ERROR("sort", 1, "array"); a = Pike_sp[-args].u.array;
ed70b71996-06-09Fredrik Hübinette (Hubbe) 
0c49782003-04-27Martin Stjernholm  for(e=1;e<args;e++)
ed70b71996-06-09Fredrik Hübinette (Hubbe)  {
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if(Pike_sp[e-args].type != T_ARRAY)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("sort", e+1, "array");
ed70b71996-06-09Fredrik Hübinette (Hubbe) 
0c49782003-04-27Martin Stjernholm  if(Pike_sp[e-args].u.array->size != a->size)
edf4d02000-07-06Fredrik Hübinette (Hubbe)  bad_arg_error("sort", Pike_sp-args, args, e+1, "array", Pike_sp+e-args,
d0d01b1999-03-20Henrik Grubbström (Grubba)  "Argument %d has wrong size.\n", (e+1));
ed70b71996-06-09Fredrik Hübinette (Hubbe)  }
3beb891996-06-21Fredrik Hübinette (Hubbe)  if(args > 1) {
0c49782003-04-27Martin Stjernholm  order = stable_sort_array_destructively(a); for(e=1;e<args;e++) order_array(Pike_sp[e-args].u.array,order);
3beb891996-06-21Fredrik Hübinette (Hubbe)  pop_n_elems(args-1);
0c49782003-04-27Martin Stjernholm  free((char *)order); } else { /* If there are only simple types in the array we can use unstable * sorting. */
caa6762003-04-27Martin Stjernholm  array_fix_unfinished_type_field (a);
0c49782003-04-27Martin Stjernholm  if (a->type_field & BIT_COMPLEX) free (stable_sort_array_destructively (a)); else sort_array_destructively (a);
3beb891996-06-21Fredrik Hübinette (Hubbe)  }
ed70b71996-06-09Fredrik Hübinette (Hubbe) }
ed1cc32001-01-09Henrik Grubbström (Grubba) /*! @decl array rows(mixed data, array index) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Select a set of rows from an array.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function is en optimized equivalent to:
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
f79bd82003-04-01Martin Nilsson  *! @code *! map(@[index], lambda(mixed x) { return @[data][x]; }) *! @endcode
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! That is, it indices data on every index in the array index and *! returns an array with the results.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[column()]
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_rows(INT32 args)
ed70b71996-06-09Fredrik Hübinette (Hubbe) { INT32 e; struct array *a,*tmp;
d0d01b1999-03-20Henrik Grubbström (Grubba)  struct svalue *val;
2523ce2003-04-28Martin Stjernholm  TYPE_FIELD types;
ed70b71996-06-09Fredrik Hübinette (Hubbe) 
d0d01b1999-03-20Henrik Grubbström (Grubba)  get_all_args("rows", args, "%*%a", &val, &tmp);
ed70b71996-06-09Fredrik Hübinette (Hubbe) 
8669721999-08-02Fredrik Hübinette (Hubbe)  /* Optimization */ if(tmp->refs == 1) { struct svalue sval; tmp->type_field = BIT_MIXED | BIT_UNFINISHED;
2523ce2003-04-28Martin Stjernholm  types = 0;
8669721999-08-02Fredrik Hübinette (Hubbe)  for(e=0;e<tmp->size;e++) { index_no_free(&sval, val, ITEM(tmp)+e);
2523ce2003-04-28Martin Stjernholm  types |= 1 << sval.type;
8669721999-08-02Fredrik Hübinette (Hubbe)  free_svalue(ITEM(tmp)+e);
2523ce2003-04-28Martin Stjernholm  move_svalue (ITEM(tmp) + e, &sval);
8669721999-08-02Fredrik Hübinette (Hubbe)  }
2523ce2003-04-28Martin Stjernholm  tmp->type_field = types;
8669721999-08-02Fredrik Hübinette (Hubbe)  stack_swap(); pop_stack(); return; }
ed70b71996-06-09Fredrik Hübinette (Hubbe) 
8669721999-08-02Fredrik Hübinette (Hubbe)  push_array(a=allocate_array(tmp->size));
2523ce2003-04-28Martin Stjernholm  types = 0; for(e=0;e<a->size;e++) {
d0d01b1999-03-20Henrik Grubbström (Grubba)  index_no_free(ITEM(a)+e, val, ITEM(tmp)+e);
2523ce2003-04-28Martin Stjernholm  types |= 1 << ITEM(a)[e].type; } a->type_field = types;
8669721999-08-02Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  Pike_sp--; dmalloc_touch_svalue(Pike_sp);
d0d01b1999-03-20Henrik Grubbström (Grubba)  pop_n_elems(args);
ed70b71996-06-09Fredrik Hübinette (Hubbe)  push_array(a); }
768f532002-11-25Martin Nilsson /*! @decl void verify_internals() *! @belongs Debug
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Perform sanity checks.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function goes through most of the internal Pike structures and *! generates a fatal error if one of them is found to be out of order. *! It is only used for debugging.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @note
50d97a2003-02-01Martin Stjernholm  *! This function does a more thorough check if the Pike runtime has *! been compiled with RTL debug.
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f__verify_internals(INT32 args)
ed70b71996-06-09Fredrik Hübinette (Hubbe) {
05590d1998-04-23Fredrik Hübinette (Hubbe)  INT32 tmp=d_flag;
8111162003-09-07Martin Nilsson  ASSERT_SECURITY_ROOT("_verify_internals");
20ee332003-09-08Martin Stjernholm  /* Keep below calls to low_thorough_check_short_svalue, or else we * get O(n!) or so, where n is the number of allocated things. */ d_flag = 49;
50d97a2003-02-01Martin Stjernholm #ifdef PIKE_DEBUG do_debug(); /* Calls do_gc() since d_flag > 3. */ #else
7458da2003-02-02Martin Stjernholm  do_gc(NULL, 1);
50d97a2003-02-01Martin Stjernholm #endif
ed70b71996-06-09Fredrik Hübinette (Hubbe)  d_flag=tmp; pop_n_elems(args); }
50d97a2003-02-01Martin Stjernholm #ifdef PIKE_DEBUG
768f532002-11-25Martin Nilsson /*! @decl int debug(int(0..) level) *! @belongs Debug
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Set the run-time debug level.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @returns
554e222001-05-06Henrik Grubbström (Grubba)  *! The old debug level will be returned.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @note
554e222001-05-06Henrik Grubbström (Grubba)  *! This function is only available if the Pike runtime has been compiled *! with RTL debug.
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f__debug(INT32 args)
a03d951997-10-14Fredrik Hübinette (Hubbe) {
5665ab1999-07-28Henrik Grubbström (Grubba)  INT_TYPE d;
8111162003-09-07Martin Nilsson  ASSERT_SECURITY_ROOT("_debug");
5665ab1999-07-28Henrik Grubbström (Grubba)  get_all_args("_debug", args, "%i", &d);
a03d951997-10-14Fredrik Hübinette (Hubbe)  pop_n_elems(args);
5665ab1999-07-28Henrik Grubbström (Grubba)  push_int(d_flag); d_flag = d;
a03d951997-10-14Fredrik Hübinette (Hubbe) }
768f532002-11-25Martin Nilsson /*! @decl int optimizer_debug(int(0..) level) *! @belongs Debug
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Set the optimizer debug level.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @returns
554e222001-05-06Henrik Grubbström (Grubba)  *! The old optimizer debug level will be returned.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @note
554e222001-05-06Henrik Grubbström (Grubba)  *! This function is only available if the Pike runtime has been compiled *! with RTL debug.
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f__optimizer_debug(INT32 args)
bcc9181999-11-14Henrik Grubbström (Grubba) { INT_TYPE l;
8111162003-09-07Martin Nilsson  ASSERT_SECURITY_ROOT("_optimizer_debug");
bcc9181999-11-14Henrik Grubbström (Grubba)  get_all_args("_optimizer_debug", args, "%i", &l); pop_n_elems(args); push_int(l_flag); l_flag = l; }
3dba602001-01-11Henrik Grubbström (Grubba) 
768f532002-11-25Martin Nilsson /*! @decl int assembler_debug(int(0..) level) *! @belongs Debug
3dba602001-01-11Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Set the assembler debug level.
3dba602001-01-11Henrik Grubbström (Grubba)  *! *! @returns
554e222001-05-06Henrik Grubbström (Grubba)  *! The old assembler debug level will be returned.
3dba602001-01-11Henrik Grubbström (Grubba)  *! *! @note
554e222001-05-06Henrik Grubbström (Grubba)  *! This function is only available if the Pike runtime has been compiled *! with RTL debug.
3dba602001-01-11Henrik Grubbström (Grubba)  */ PMOD_EXPORT void f__assembler_debug(INT32 args) { INT_TYPE l;
8111162003-09-07Martin Nilsson  ASSERT_SECURITY_ROOT("_assembler_debug");
3dba602001-01-11Henrik Grubbström (Grubba) 
6933442002-05-14Henrik Grubbström (Grubba)  get_all_args("_assembler_debug", args, "%i", &l);
3dba602001-01-11Henrik Grubbström (Grubba)  pop_n_elems(args); push_int(a_flag); a_flag = l; }
2f54f71998-04-13Henrik Grubbström (Grubba) #ifdef YYDEBUG
768f532002-11-25Martin Nilsson /*! @decl int compiler_trace(int(0..) level) *! @belongs Debug
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Set the compiler trace level.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @returns
554e222001-05-06Henrik Grubbström (Grubba)  *! The old compiler trace level will be returned.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @note
554e222001-05-06Henrik Grubbström (Grubba)  *! This function is only available if the Pike runtime has been compiled *! with RTL debug.
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f__compiler_trace(INT32 args)
2f54f71998-04-13Henrik Grubbström (Grubba) { extern int yydebug;
5665ab1999-07-28Henrik Grubbström (Grubba)  INT_TYPE yyd;
8111162003-09-07Martin Nilsson  ASSERT_SECURITY_ROOT("_compiler_trace");
5665ab1999-07-28Henrik Grubbström (Grubba)  get_all_args("_compiler_trace", args, "%i", &yyd);
2f54f71998-04-13Henrik Grubbström (Grubba)  pop_n_elems(args);
5665ab1999-07-28Henrik Grubbström (Grubba)  push_int(yydebug); yydebug = yyd;
2f54f71998-04-13Henrik Grubbström (Grubba) } #endif /* YYDEBUG */
ed70b71996-06-09Fredrik Hübinette (Hubbe) #endif
fe91501998-07-26Peter J. Holzer #if defined(HAVE_LOCALTIME) || defined(HAVE_GMTIME) static void encode_struct_tm(struct tm *tm)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
f0e6f12003-12-06Martin Nilsson  push_text("sec");
3beb891996-06-21Fredrik Hübinette (Hubbe)  push_int(tm->tm_sec);
f0e6f12003-12-06Martin Nilsson  push_text("min");
3beb891996-06-21Fredrik Hübinette (Hubbe)  push_int(tm->tm_min);
f0e6f12003-12-06Martin Nilsson  push_text("hour");
3beb891996-06-21Fredrik Hübinette (Hubbe)  push_int(tm->tm_hour);
7bd0ea1996-02-19Fredrik Hübinette (Hubbe) 
f0e6f12003-12-06Martin Nilsson  push_text("mday");
3beb891996-06-21Fredrik Hübinette (Hubbe)  push_int(tm->tm_mday);
f0e6f12003-12-06Martin Nilsson  push_text("mon");
3beb891996-06-21Fredrik Hübinette (Hubbe)  push_int(tm->tm_mon);
f0e6f12003-12-06Martin Nilsson  push_text("year");
3beb891996-06-21Fredrik Hübinette (Hubbe)  push_int(tm->tm_year);
f0e6f12003-12-06Martin Nilsson  push_text("wday");
3beb891996-06-21Fredrik Hübinette (Hubbe)  push_int(tm->tm_wday);
f0e6f12003-12-06Martin Nilsson  push_text("yday");
3beb891996-06-21Fredrik Hübinette (Hubbe)  push_int(tm->tm_yday);
f0e6f12003-12-06Martin Nilsson  push_text("isdst");
3beb891996-06-21Fredrik Hübinette (Hubbe)  push_int(tm->tm_isdst);
fe91501998-07-26Peter J. Holzer } #endif #ifdef HAVE_GMTIME
ed1cc32001-01-09Henrik Grubbström (Grubba) /*! @decl mapping(string:int) gmtime(int timestamp) *!
df0f872003-04-14Martin Stjernholm  *! Convert seconds since 00:00:00 UTC, Jan 1, 1970 into components.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function works like @[localtime()] but the result is *! not adjusted for the local time zone.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[localtime()], @[time()], @[ctime()], @[mktime()]
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_gmtime(INT32 args)
fe91501998-07-26Peter J. Holzer { struct tm *tm;
d0d01b1999-03-20Henrik Grubbström (Grubba)  INT_TYPE tt;
fe91501998-07-26Peter J. Holzer  time_t t;
d0d01b1999-03-20Henrik Grubbström (Grubba)  get_all_args("gmtime", args, "%i", &tt); t = tt; tm = gmtime(&t);
f917a32002-10-03Martin Stjernholm  if (!tm) Pike_error ("gmtime() on this system cannot handle " "the timestamp %ld.\n", (long) t);
fe91501998-07-26Peter J. Holzer  pop_n_elems(args); encode_struct_tm(tm);
f0e6f12003-12-06Martin Nilsson  push_text("timezone");
fe91501998-07-26Peter J. Holzer  push_int(0); f_aggregate_mapping(20); } #endif #ifdef HAVE_LOCALTIME
ed1cc32001-01-09Henrik Grubbström (Grubba) /*! @decl mapping(string:int) localtime(int timestamp) *!
df0f872003-04-14Martin Stjernholm  *! Convert seconds since 00:00:00 UTC, 1 Jan 1970 into components.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @returns
554e222001-05-06Henrik Grubbström (Grubba)  *! This function returns a mapping with the following components: *! @mapping *! @member int(0..60) "sec" *! Seconds over the minute. *! @member int(0..59) "min" *! Minutes over the hour. *! @member int(0..23) "hour" *! Hour of the day. *! @member int(1..31) "mday" *! Day of the month. *! @member int(0..11) "mon" *! Month of the year. *! @member int(0..) "year" *! Year since 1900. *! @member int(0..6) "wday" *! Day of week (0 = Sunday). *! @member int(0..365) "yday" *! Day of the year. *! @member int(0..1) "isdst" *! Is daylight savings time. *! @member int "timezone"
69a3422004-04-01Henrik Grubbström (Grubba)  *! Offset from UTC, including daylight savings time adjustment.
554e222001-05-06Henrik Grubbström (Grubba)  *! @endmapping
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
f917a32002-10-03Martin Stjernholm  *! An error is thrown if the localtime(2) call failed on the system.
b5b1b22002-10-03Martin Stjernholm  *! It's platform dependent what time ranges that function can handle, *! e.g. Windows doesn't handle a negative @[timestamp]. *!
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! @note
69a3422004-04-01Henrik Grubbström (Grubba)  *! Prior to Pike 7.5 the field @expr{"timezone"@} was sometimes not *! present, and was sometimes not adjusted for daylight savings time.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[Calendar], @[gmtime()], @[time()], @[ctime()], @[mktime()]
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_localtime(INT32 args)
fe91501998-07-26Peter J. Holzer { struct tm *tm;
d0d01b1999-03-20Henrik Grubbström (Grubba)  INT_TYPE tt;
fe91501998-07-26Peter J. Holzer  time_t t;
d0d01b1999-03-20Henrik Grubbström (Grubba)  get_all_args("localtime", args, "%i", &tt); t = tt; tm = localtime(&t);
f917a32002-10-03Martin Stjernholm  if (!tm) Pike_error ("localtime() on this system cannot handle " "the timestamp %ld.\n", (long) t);
fe91501998-07-26Peter J. Holzer  pop_n_elems(args); encode_struct_tm(tm);
3beb891996-06-21Fredrik Hübinette (Hubbe) 
f0e6f12003-12-06Martin Nilsson  push_text("timezone");
69a3422004-04-01Henrik Grubbström (Grubba) #ifdef STRUCT_TM_HAS_GMTOFF
47ba812002-03-21Henrik Grubbström (Grubba)  push_int(-tm->tm_gmtoff);
69a3422004-04-01Henrik Grubbström (Grubba) #elif defined(STRUCT_TM_HAS___TM_GMTOFF)
47ba812002-03-21Henrik Grubbström (Grubba)  push_int(-tm->__tm_gmtoff);
69a3422004-04-01Henrik Grubbström (Grubba) #elif defined(HAVE_EXTERNAL_TIMEZONE) /* Assume dst is one hour. */ push_int(timezone - 3600*tm->tm_isdst);
3beb891996-06-21Fredrik Hübinette (Hubbe) #else
69a3422004-04-01Henrik Grubbström (Grubba)  /* Assume dst is one hour. */ push_int(-3600*tm->tm_isdst);
47ba812002-03-21Henrik Grubbström (Grubba) #endif
69a3422004-04-01Henrik Grubbström (Grubba)  f_aggregate_mapping(20);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
3beb891996-06-21Fredrik Hübinette (Hubbe) #endif
5267b71995-08-09Fredrik Hübinette (Hubbe) 
a7c4d92004-01-30Henrik Grubbström (Grubba) #ifdef HAVE_GMTIME /* Returns the approximate difference in seconds between the * two struct tm's. */ static time_t my_tm_diff(const struct tm *t1, const struct tm *t2) {
9cc3d62004-02-03Henrik Grubbström (Grubba)  time_t base = (t1->tm_year - t2->tm_year) * 32140800 + (t1->tm_mon - t2->tm_mon) * 2678400 +
a7c4d92004-01-30Henrik Grubbström (Grubba)  (t1->tm_mday - t2->tm_mday) * 86400 + (t1->tm_hour - t2->tm_hour) * 3600 + (t1->tm_min - t2->tm_min) * 60 + (t1->tm_sec - t2->tm_sec);
9cc3d62004-02-03Henrik Grubbström (Grubba)  if ((t1->tm_year > t2->tm_year) && (base < 0)) return 0x7fffffff; if ((t1->tm_year < t2->tm_year) && (base > 0)) return -0x7fffffff;
0083c12004-02-02Henrik Grubbström (Grubba)  return base;
a7c4d92004-01-30Henrik Grubbström (Grubba) } /* Inverse operation of gmtime(). */ static time_t my_timegm(struct tm *target_tm) { time_t current_ts = 0; time_t diff_ts; struct tm *current_tm; int loop_cnt = 0; /* This loop seems stable, and usually converges in two passes. * The loop counter is for paranoia reasons. */ while((diff_ts = my_tm_diff(target_tm, current_tm = gmtime(&current_ts)))) { current_ts += diff_ts; loop_cnt++;
60297a2004-02-03Henrik Grubbström (Grubba)  /* fprintf(stderr, "Loop [%d]: %d, %d\n", loop_cnt, current_ts, diff_ts); */
a7c4d92004-01-30Henrik Grubbström (Grubba)  if (loop_cnt > 20) { /* Infinite loop? */ return -1; } } /* Check that the result tm looks like what we expect... */ if ((current_tm->tm_sec == target_tm->tm_sec) && (current_tm->tm_min == target_tm->tm_min)) { /* Odds are that the rest of the fields are correct (1:3600). */ return current_ts; } return -1; } #endif /* HAVE_GMTIME */
b5d2dc1997-01-27Fredrik Hübinette (Hubbe) #ifdef HAVE_MKTIME
ed1cc32001-01-09Henrik Grubbström (Grubba) /*! @decl int mktime(mapping(string:int) tm)
3254e12001-02-06Henrik Grubbström (Grubba)  *! @decl int mktime(int sec, int min, int hour, int mday, int mon, int year, @
f3f0e82003-04-27Henrik Grubbström (Grubba)  *! int|void isdst, int|void tz)
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function converts information about date and time into an integer
df0f872003-04-14Martin Stjernholm  *! which contains the number of seconds since 00:00:00 UTC, Jan 1, 1970.
554e222001-05-06Henrik Grubbström (Grubba)  *! *! You can either call this function with a mapping containing the *! following elements: *! @mapping *! @member int(0..60) "sec" *! Seconds over the minute. *! @member int(0..59) "min" *! Minutes over the hour. *! @member int(0..23) "hour" *! Hour of the day. *! @member int(1..31) "mday" *! Day of the month. *! @member int(0..11) "mon" *! Month of the year. *! @member int(0..) "year" *! Year since 1900. *! @member int(0..1) "isdst" *! Is daylight savings time.
06a3ac2002-05-12Martin Nilsson  *! @member int "timezone"
7792712002-03-21Henrik Grubbström (Grubba)  *! The timezone offset from UTC in seconds. If left out, the time *! will be calculated in the local timezone.
554e222001-05-06Henrik Grubbström (Grubba)  *! @endmapping *! *! Or you can just send them all on one line as the second syntax suggests.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
081eea2002-09-09Henrik Grubbström (Grubba)  *! @note
df0f872003-04-14Martin Stjernholm  *! On some operating systems (notably AIX), dates before 00:00:00 *! UTC, Jan 1, 1970 are not supported.
081eea2002-09-09Henrik Grubbström (Grubba)  *! *! On most systems, the supported range of dates are Dec 13, 1901 *! 20:45:52 UTC through Jan 19, 2038 03:14:07 UTC (inclusive). *!
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[time()], @[ctime()], @[localtime()], @[gmtime()]
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_mktime (INT32 args)
b5d2dc1997-01-27Fredrik Hübinette (Hubbe) {
1f88bf2001-09-24Henrik Grubbström (Grubba)  INT_TYPE sec, min, hour, mday, mon, year;
2adf002004-02-29Martin Stjernholm  INT_TYPE isdst = -1, tz;
b5d2dc1997-01-27Fredrik Hübinette (Hubbe)  struct tm date;
03a77e2002-10-15Henrik Grubbström (Grubba)  int retval;
1f88bf2001-09-24Henrik Grubbström (Grubba) 
b5d2dc1997-01-27Fredrik Hübinette (Hubbe)  if (args<1)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_TOO_FEW_ARGS_ERROR("mktime", 1);
b5d2dc1997-01-27Fredrik Hübinette (Hubbe)  if(args == 1) { MEMSET(&date, 0, sizeof(date)); push_text("sec"); push_text("min"); push_text("hour"); push_text("mday"); push_text("mon"); push_text("year"); push_text("isdst"); push_text("timezone"); f_aggregate(8); f_rows(2);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  Pike_sp--; dmalloc_touch_svalue(Pike_sp); push_array_items(Pike_sp->u.array);
b5d2dc1997-01-27Fredrik Hübinette (Hubbe)  args=8; }
2adf002004-02-29Martin Stjernholm  get_all_args("mktime",args, "%i%i%i%i%i%i.%i%i", &sec, &min, &hour, &mday, &mon, &year, &isdst, &tz);
b5d2dc1997-01-27Fredrik Hübinette (Hubbe) 
5db18e1998-05-07Fredrik Hübinette (Hubbe)  MEMSET(&date, 0, sizeof(date));
b5d2dc1997-01-27Fredrik Hübinette (Hubbe)  date.tm_sec=sec; date.tm_min=min; date.tm_hour=hour; date.tm_mday=mday; date.tm_mon=mon; date.tm_year=year;
2adf002004-02-29Martin Stjernholm  date.tm_isdst=isdst;
b5d2dc1997-01-27Fredrik Hübinette (Hubbe) 
ca16832004-01-30Henrik Grubbström (Grubba)  /* date.tm_zone = NULL; */
a7c4d92004-01-30Henrik Grubbström (Grubba)  #ifdef HAVE_GMTIME
2adf002004-02-29Martin Stjernholm  if(args > 7)
a7c4d92004-01-30Henrik Grubbström (Grubba)  { /* UTC-relative time. Use my_timegm(). */ retval = my_timegm(&date); if (retval == -1) PIKE_ERROR("mktime", "Cannot convert.\n", Pike_sp, args);
2adf002004-02-29Martin Stjernholm  retval += tz;
a7c4d92004-01-30Henrik Grubbström (Grubba)  } else { #endif /* HAVE_GMTIME */
7792712002-03-21Henrik Grubbström (Grubba) #ifdef STRUCT_TM_HAS_GMTOFF
a7c4d92004-01-30Henrik Grubbström (Grubba)  /* BSD-style */ date.tm_gmtoff = 0;
7792712002-03-21Henrik Grubbström (Grubba) #else #ifdef STRUCT_TM_HAS___TM_GMTOFF
a7c4d92004-01-30Henrik Grubbström (Grubba)  /* Linux-style */ date.__tm_gmtoff = 0;
419d492002-09-07Henrik Grubbström (Grubba) #else
2adf002004-02-29Martin Stjernholm  if(args > 7)
a7c4d92004-01-30Henrik Grubbström (Grubba)  { /* Pre-adjust for the timezone. * * Note that pre-adjustment must be done on AIX for dates * near Jan 1, 1970, sine AIX mktime(3) doesn't support * negative time. */
2adf002004-02-29Martin Stjernholm  date.tm_sec += tz
419d492002-09-07Henrik Grubbström (Grubba) #ifdef HAVE_EXTERNAL_TIMEZONE
a7c4d92004-01-30Henrik Grubbström (Grubba)  - timezone
419d492002-09-07Henrik Grubbström (Grubba) #endif /* HAVE_EXTERNAL_TIMEZONE */
a7c4d92004-01-30Henrik Grubbström (Grubba)  ; }
7792712002-03-21Henrik Grubbström (Grubba) #endif /* STRUCT_TM_HAS___TM_GMTOFF */ #endif /* STRUCT_TM_HAS_GMTOFF */
a7c4d92004-01-30Henrik Grubbström (Grubba)  retval = mktime(&date);
7792712002-03-21Henrik Grubbström (Grubba) 
a7c4d92004-01-30Henrik Grubbström (Grubba)  if (retval == -1) PIKE_ERROR("mktime", "Cannot convert.\n", Pike_sp, args);
03a77e2002-10-15Henrik Grubbström (Grubba) 
419d492002-09-07Henrik Grubbström (Grubba) #if defined(STRUCT_TM_HAS_GMTOFF) || defined(STRUCT_TM_HAS___TM_GMTOFF)
2adf002004-02-29Martin Stjernholm  if(args > 7)
a7c4d92004-01-30Henrik Grubbström (Grubba)  { /* Post-adjust for the timezone. * * Note that tm_gmtoff has the opposite sign of timezone. * * Note also that it must be post-adjusted, since the gmtoff * field is set by mktime(3). */
7792712002-03-21Henrik Grubbström (Grubba) #ifdef STRUCT_TM_HAS_GMTOFF
2adf002004-02-29Martin Stjernholm  retval += tz + date.tm_gmtoff;
7792712002-03-21Henrik Grubbström (Grubba) #else
2adf002004-02-29Martin Stjernholm  retval += tz + date.__tm_gmtoff;
7792712002-03-21Henrik Grubbström (Grubba) #endif /* STRUCT_TM_HAS_GMTOFF */
a7c4d92004-01-30Henrik Grubbström (Grubba)  }
b5d2dc1997-01-27Fredrik Hübinette (Hubbe) 
2adf002004-02-29Martin Stjernholm  if ((isdst != -1) && (isdst != date.tm_isdst)) {
a7c4d92004-01-30Henrik Grubbström (Grubba)  /* Some stupid libc's (Hi Linux!) don't accept that we've set isdst... */
2adf002004-02-29Martin Stjernholm  retval += 3600 * (isdst - date.tm_isdst);
a7c4d92004-01-30Henrik Grubbström (Grubba)  }
6b402e2002-10-15Henrik Grubbström (Grubba) #endif /* STRUCT_TM_HAS_GMTOFF || STRUCT_TM_HAS___TM_GMTOFF */
a7c4d92004-01-30Henrik Grubbström (Grubba) #ifdef HAVE_GMTIME } #endif /* HAVE_GMTIME */
03a77e2002-10-15Henrik Grubbström (Grubba) 
c69e411999-12-06Henrik Grubbström (Grubba)  pop_n_elems(args); push_int(retval);
b5d2dc1997-01-27Fredrik Hübinette (Hubbe) } #endif
42a92c1999-11-04Henrik Grubbström (Grubba) /* Parse a sprintf/sscanf-style format string */
93b7202000-08-14Henrik Grubbström (Grubba) static ptrdiff_t low_parse_format(p_wchar0 *s, ptrdiff_t slen)
42a92c1999-11-04Henrik Grubbström (Grubba) {
93b7202000-08-14Henrik Grubbström (Grubba)  ptrdiff_t i; ptrdiff_t offset = 0;
edf4d02000-07-06Fredrik Hübinette (Hubbe)  struct svalue *old_sp = Pike_sp;
42a92c1999-11-04Henrik Grubbström (Grubba)  for (i=offset; i < slen; i++) { if (s[i] == '%') {
93b7202000-08-14Henrik Grubbström (Grubba)  ptrdiff_t j;
42a92c1999-11-04Henrik Grubbström (Grubba)  if (i != offset) { push_string(make_shared_binary_string0(s + offset, i));
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if ((Pike_sp != old_sp+1) && (Pike_sp[-2].type == T_STRING)) {
42a92c1999-11-04Henrik Grubbström (Grubba)  /* Concat. */ f_add(2); } } for (j = i+1;j<slen;j++) { int c = s[j]; switch(c) { /* Flags */ case '!': case '#': case '$': case '-': case '/': case '0': case '=': case '>': case '@': case '^': case '_': case '|': continue; /* Padding */ case ' ': case '\'': case '+': case '~':
782a902003-09-11Henrik Grubbström (Grubba)  continue;
42a92c1999-11-04Henrik Grubbström (Grubba)  /* Attributes */ case '.': case ':': case ';': continue; /* Attribute value */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': continue; /* Specials */ case '%': push_constant_text("%");
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if ((Pike_sp != old_sp+1) && (Pike_sp[-2].type == T_STRING)) {
42a92c1999-11-04Henrik Grubbström (Grubba)  /* Concat. */ f_add(2); } break; case '{': i = j + 1 + low_parse_format(s + j + 1, slen - (j+1)); f_aggregate(1); if ((i + 2 >= slen) || (s[i] != '%') || (s[i+1] != '}')) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("parse_format(): Expected %%}.\n");
42a92c1999-11-04Henrik Grubbström (Grubba)  } i += 2; break; case '}':
93b7202000-08-14Henrik Grubbström (Grubba)  f_aggregate(DO_NOT_WARN(Pike_sp - old_sp));
42a92c1999-11-04Henrik Grubbström (Grubba)  return i; /* Set */ case '[': break; /* Argument */ default: break; } break; } if (j == slen) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("parse_format(): Unterminated %%-expression.\n");
42a92c1999-11-04Henrik Grubbström (Grubba)  } offset = i = j; } } if (i != offset) { push_string(make_shared_binary_string0(s + offset, i));
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if ((Pike_sp != old_sp+1) && (Pike_sp[-2].type == T_STRING)) {
42a92c1999-11-04Henrik Grubbström (Grubba)  /* Concat. */ f_add(2); } }
93b7202000-08-14Henrik Grubbström (Grubba)  f_aggregate(DO_NOT_WARN(Pike_sp - old_sp));
42a92c1999-11-04Henrik Grubbström (Grubba)  return i; }
49c3f92003-09-11Johan Sundström /** @decl array parse_format(string fmt) ** ** Parses a sprintf/sscanf-style format string
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
42a92c1999-11-04Henrik Grubbström (Grubba) static void f_parse_format(INT32 args) { struct pike_string *s = NULL; struct array *a;
93b7202000-08-14Henrik Grubbström (Grubba)  ptrdiff_t len;
42a92c1999-11-04Henrik Grubbström (Grubba)  get_all_args("parse_format", args, "%W", &s); len = low_parse_format(STR0(s), s->len); if (len != s->len) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("parse_format(): Unexpected %%} in format string at offset %ld\n",
69bb402000-08-17Henrik Grubbström (Grubba)  PTRDIFF_T_TO_LONG(len));
42a92c1999-11-04Henrik Grubbström (Grubba)  } #ifdef PIKE_DEBUG
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if (Pike_sp[-1].type != T_ARRAY) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("parse_format(): Unexpected result from low_parse_format()\n");
42a92c1999-11-04Henrik Grubbström (Grubba)  } #endif /* PIKE_DEBUG */
edf4d02000-07-06Fredrik Hübinette (Hubbe)  a = (--Pike_sp)->u.array;
42a92c1999-11-04Henrik Grubbström (Grubba)  debug_malloc_touch(a); pop_n_elems(args); push_array(a); }
5267b71995-08-09Fredrik Hübinette (Hubbe) 
156fd51997-10-27Fredrik Hübinette (Hubbe) /* Check if the string s[0..len[ matches the glob m[0..mlen[ */
0bc4cf1998-10-13Fredrik Hübinette (Hubbe) static int does_match(struct pike_string *s,int j, struct pike_string *m,int i)
ed70b71996-06-09Fredrik Hübinette (Hubbe) {
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  for (; i<m->len; i++)
ed70b71996-06-09Fredrik Hübinette (Hubbe)  {
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  switch (index_shared_string(m,i))
ed70b71996-06-09Fredrik Hübinette (Hubbe)  {
7a1bed1996-12-01Fredrik Hübinette (Hubbe)  case '?':
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  if(j++>=s->len) return 0;
7a1bed1996-12-01Fredrik Hübinette (Hubbe)  break;
ed70b71996-06-09Fredrik Hübinette (Hubbe)  case '*': i++;
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  if (i==m->len) return 1; /* slut */
ed70b71996-06-09Fredrik Hübinette (Hubbe) 
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  for (;j<s->len;j++) if (does_match(s,j,m,i))
ed70b71996-06-09Fredrik Hübinette (Hubbe)  return 1; return 0; default:
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  if(j>=s->len || index_shared_string(m,i)!=index_shared_string(s,j)) return 0;
7a1bed1996-12-01Fredrik Hübinette (Hubbe)  j++;
ed70b71996-06-09Fredrik Hübinette (Hubbe)  } }
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  return j==s->len;
ed70b71996-06-09Fredrik Hübinette (Hubbe) }
ed1cc32001-01-09Henrik Grubbström (Grubba) /*! @decl int(0..1) glob(string glob, string str) *! @decl array(string) glob(string glob, array(string) arr) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Match strings against globs.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! In a glob string a question sign matches any character and *! an asterisk matches any string.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! When the second argument is a string and @[str] matches
cbe8c92003-04-07Martin Nilsson  *! the glob @[glob] @expr{1@} will be returned, @expr{0@} (zero) otherwise.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! If the second array is an array and array containing the strings in *! @[arr] that match @[glob] will be returned.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[sscanf()], @[Regexp]
ed1cc32001-01-09Henrik Grubbström (Grubba)  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_glob(INT32 args)
ed70b71996-06-09Fredrik Hübinette (Hubbe) { INT32 i,matches; struct array *a;
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *glob;
ed70b71996-06-09Fredrik Hübinette (Hubbe)  if(args < 2)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_TOO_FEW_ARGS_ERROR("glob", 2);
ed70b71996-06-09Fredrik Hübinette (Hubbe) 
d0d01b1999-03-20Henrik Grubbström (Grubba)  if(args > 2) pop_n_elems(args-2);
3beb891996-06-21Fredrik Hübinette (Hubbe)  args=2;
ed70b71996-06-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  if (Pike_sp[-args].type!=T_STRING)
d0d01b1999-03-20Henrik Grubbström (Grubba)  SIMPLE_BAD_ARG_ERROR("glob", 1, "string");
ed70b71996-06-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  glob=Pike_sp[-args].u.string;
ed70b71996-06-09Fredrik Hübinette (Hubbe) 
edf4d02000-07-06Fredrik Hübinette (Hubbe)  switch(Pike_sp[1-args].type)
ed70b71996-06-09Fredrik Hübinette (Hubbe)  { case T_STRING:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  i=does_match(Pike_sp[1-args].u.string,0,glob,0);
ed70b71996-06-09Fredrik Hübinette (Hubbe)  pop_n_elems(2); push_int(i); break; case T_ARRAY:
edf4d02000-07-06Fredrik Hübinette (Hubbe)  a=Pike_sp[1-args].u.array;
b072f22004-04-29Martin Nilsson 
2575242004-05-14Martin Nilsson  if( (a->type_field & ~BIT_STRING) && (array_fix_type_field(a) & ~BIT_STRING) ) SIMPLE_BAD_ARG_ERROR("glob", 2, "string|array(string)");
b072f22004-04-29Martin Nilsson 
3beb891996-06-21Fredrik Hübinette (Hubbe)  matches=0;
e566a82003-05-07Martin Stjernholm  check_stack(120); BEGIN_AGGREGATE_ARRAY (MINIMUM (a->size, 120)) { for(i=0;i<a->size;i++) if(does_match(ITEM(a)[i].u.string,0,glob,0)) { ref_push_string(ITEM(a)[i].u.string); matches++; DO_AGGREGATE_ARRAY (120); } } END_AGGREGATE_ARRAY; Pike_sp[-1].u.array->type_field = BIT_STRING; stack_pop_n_elems_keep_top (2);
ed70b71996-06-09Fredrik Hübinette (Hubbe)  break; default:
e566a82003-05-07Martin Stjernholm  SIMPLE_BAD_ARG_ERROR("glob", 2, "string|array(string)");
ed70b71996-06-09Fredrik Hübinette (Hubbe)  } }
a7759e1998-11-17Henrik Grubbström (Grubba) /* comb_merge */
7cb4e42001-01-09Henrik Grubbström (Grubba) /*! @module Array */ /*! @decl array(int) interleave_array(array(mapping(int:mixed)) tab) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Interleave a sparse matrix.
7cb4e42001-01-09Henrik Grubbström (Grubba)  *!
a8cdf92004-04-29Martin Nilsson  *! Returns an array with offsets that describe how to shift the *! rows of @[tab] so that only at most one non-zero value exists in *! every column.
7cb4e42001-01-09Henrik Grubbström (Grubba)  */
a7759e1998-11-17Henrik Grubbström (Grubba) static void f_interleave_array(INT32 args) { struct array *arr = NULL; struct array *min = NULL; struct array *order = NULL; int max = 0; int nelems = 0; int i; get_all_args("interleave_array", args, "%a", &arr); /* We're not interrested in any other arguments. */ pop_n_elems(args-1);
2575242004-05-14Martin Nilsson  if( (arr->type_field & ~BIT_MAPPING) && (array_fix_type_field(arr) & ~BIT_MAPPING) ) SIMPLE_BAD_ARG_ERROR("interleave_array", 1, "array(mapping(int:mixed))");
a7759e1998-11-17Henrik Grubbström (Grubba)  /* The order array */ ref_push_array(arr); f_indices(1);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  order = Pike_sp[-1].u.array;
a7759e1998-11-17Henrik Grubbström (Grubba)  /* The min array */ push_array(min = allocate_array(arr->size)); /* Initialize the min array */ for (i = 0; i < arr->size; i++) {
fa666b2004-04-15Martin Nilsson  struct mapping_data *md; /* e and k are used by NEW_MAPPING_LOOP() */
a7759e1998-11-17Henrik Grubbström (Grubba)  INT32 e; struct keypair *k;
a63b362003-11-07Martin Stjernholm  INT_TYPE low = MAX_INT_TYPE;
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
a7759e1998-11-17Henrik Grubbström (Grubba)  if (ITEM(arr)[i].type != T_MAPPING) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("interleave_array(): Element %d is not a mapping!\n", i);
a7759e1998-11-17Henrik Grubbström (Grubba)  }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #endif /* PIKE_DEBUG */
fa666b2004-04-15Martin Nilsson  md = ITEM(arr)[i].u.mapping->data; NEW_MAPPING_LOOP(md) {
a7759e1998-11-17Henrik Grubbström (Grubba)  if (k->ind.type != T_INT) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("interleave_array(): Index not an integer in mapping %d!\n", i);
a7759e1998-11-17Henrik Grubbström (Grubba)  } if (low > k->ind.u.integer) { low = k->ind.u.integer; if (low < 0) {
69aa4b2003-01-26Mirar (Pontus Hagland)  Pike_error("interleave_array(): Index %"PRINTPIKEINT"d in mapping %d is negative!\n",
a7759e1998-11-17Henrik Grubbström (Grubba)  low, i); } } if (max < k->ind.u.integer) { max = k->ind.u.integer; } nelems++; } ITEM(min)[i].u.integer = low; }
fc4a8e2004-05-02Martin Nilsson  min->type_field = BIT_INT;
a7759e1998-11-17Henrik Grubbström (Grubba)  ref_push_array(order); f_sort(2); /* Sort the order array on the minimum index */ /* State on stack now: * * array(mapping(int:mixed)) arr * array(int) order * array(int) min (now sorted) */ /* Now we can start with the real work... */ { char *tab; int size; int minfree = 0; /* Initialize the lookup table */ max += 1; max *= 2; /* max will be the padding at the end. */ size = (nelems + max) * 8; /* Initial size */ if (!(tab = malloc(size + max))) {
54db6c1999-03-27Henrik Grubbström (Grubba)  SIMPLE_OUT_OF_MEMORY_ERROR("interleave_array", size+max);
a7759e1998-11-17Henrik Grubbström (Grubba)  } MEMSET(tab, 0, size + max); for (i = 0; i < order->size; i++) { int low = ITEM(min)[i].u.integer; int j = ITEM(order)[i].u.integer; int offset = 0;
b072f22004-04-29Martin Nilsson  int ok = 0;
a7759e1998-11-17Henrik Grubbström (Grubba)  struct mapping *m;
fa666b2004-04-15Martin Nilsson  struct mapping_data *md;
a7759e1998-11-17Henrik Grubbström (Grubba)  INT32 e; struct keypair *k;
6168ce2000-01-27Fredrik Hübinette (Hubbe)  if (! m_sizeof(m = ITEM(arr)[j].u.mapping)) {
a7759e1998-11-17Henrik Grubbström (Grubba)  /* Not available */ ITEM(min)[i].u.integer = -1; continue; } if (low < minfree) { offset = minfree - low; } else { minfree = offset; }
fa666b2004-04-15Martin Nilsson  md = m->data;
a7759e1998-11-17Henrik Grubbström (Grubba)  while (!ok) { ok = 1;
fa666b2004-04-15Martin Nilsson  NEW_MAPPING_LOOP(md) {
a7759e1998-11-17Henrik Grubbström (Grubba)  int ind = k->ind.u.integer; if (tab[offset + ind]) { ok = 0; while (tab[++offset + ind]) ; } } }
fa666b2004-04-15Martin Nilsson  NEW_MAPPING_LOOP(md) {
a7759e1998-11-17Henrik Grubbström (Grubba)  tab[offset + k->ind.u.integer] = 1; } while(tab[minfree]) { minfree++; } ITEM(min)[i].u.integer = offset; /* Check need for realloc */ if (offset >= size) { char *newtab = realloc(tab, size*2 + max); if (!newtab) { free(tab);
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("interleave_array(): Couldn't extend table!\n");
a7759e1998-11-17Henrik Grubbström (Grubba)  } tab = newtab; MEMSET(tab + size + max, 0, size); size = size * 2; } } free(tab); } /* We want these two to survive the stackpopping. */ add_ref(min); add_ref(order); pop_n_elems(3); /* Return value */ ref_push_array(min); /* Restore the order */ push_array(order); push_array(min); f_sort(2); pop_stack(); }
7ce3a91998-02-12Henrik Grubbström (Grubba) /* longest_ordered_sequence */ static int find_gt(struct array *a, int i, int *stack, int top) { struct svalue *x = a->item + i; int l,h; if (!top || !is_lt(x, a->item + stack[top - 1])) return top; l = 0; h = top; while (l < h) { int middle = (l + h)/2; if (!is_gt(a->item + stack[middle], x)) { l = middle+1; } else { h = middle; } } return l; } static struct array *longest_ordered_sequence(struct array *a) { int *stack; int *links;
9ca13e2003-06-12Martin Nilsson  int i, top=0, ltop=-1;
7ce3a91998-02-12Henrik Grubbström (Grubba)  struct array *res; ONERROR tmp; ONERROR tmp2;
c055781999-05-11Fredrik Hübinette (Hubbe)  if(!a->size) return allocate_array(0);
7ce3a91998-02-12Henrik Grubbström (Grubba)  stack = malloc(sizeof(int)*a->size); links = malloc(sizeof(int)*a->size); if (!stack || !links) { if (stack) free(stack); if (links) free(links); return 0; } /* is_gt(), is_lt() and low_allocate_array() can generate errors. */ SET_ONERROR(tmp, free, stack); SET_ONERROR(tmp2, free, links); for (i=0; i<a->size; i++) { int pos; pos = find_gt(a, i, stack, top); if (pos == top) { top++; ltop = i; } if (pos != 0) links[i] = stack[pos-1]; else links[i] = -1; stack[pos] = i; }
a4a1722000-12-05Per Hedbor  /* FIXME(?) memory unfreed upon error here */
7ce3a91998-02-12Henrik Grubbström (Grubba)  res = low_allocate_array(top, 0); while (ltop != -1) {
2523ce2003-04-28Martin Stjernholm  ITEM(res)[--top].u.integer = ltop;
7ce3a91998-02-12Henrik Grubbström (Grubba)  ltop = links[ltop]; }
fc4a8e2004-05-02Martin Nilsson  res->type_field = BIT_INT;
7ce3a91998-02-12Henrik Grubbström (Grubba)  UNSET_ONERROR(tmp2); UNSET_ONERROR(tmp); free(stack); free(links); return res; }
7cb4e42001-01-09Henrik Grubbström (Grubba) /*! @decl array(int) longest_ordered_sequence(array a) *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Find the longest ordered sequence of elements.
7cb4e42001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! This function returns an array of the indices in the longest *! ordered sequence of elements in the array.
7cb4e42001-01-09Henrik Grubbström (Grubba)  *! *! @seealso
554e222001-05-06Henrik Grubbström (Grubba)  *! @[diff()]
7cb4e42001-01-09Henrik Grubbström (Grubba)  */
7ce3a91998-02-12Henrik Grubbström (Grubba) static void f_longest_ordered_sequence(INT32 args) { struct array *a = NULL; get_all_args("Array.longest_ordered_sequence", args, "%a", &a); /* THREADS_ALLOW(); */ a = longest_ordered_sequence(a); /* THREADS_DISALLOW(); */ if (!a) {
54db6c1999-03-27Henrik Grubbström (Grubba)  SIMPLE_OUT_OF_MEMORY_ERROR("Array.longest_ordered_sequence", (int)sizeof(int *)*a->size*2);
7ce3a91998-02-12Henrik Grubbström (Grubba)  } pop_n_elems(args); push_array(a); }
088e2e1998-02-12Mirar (Pontus Hagland) /**** diff ************************************************************/
f873831998-05-19Henrik Grubbström (Grubba) static struct array* diff_compare_table(struct array *a,struct array *b,int *u)
088e2e1998-02-12Mirar (Pontus Hagland) { struct array *res; struct mapping *map; struct svalue *pval; int i;
2523ce2003-04-28Martin Stjernholm  TYPE_FIELD types;
088e2e1998-02-12Mirar (Pontus Hagland) 
f873831998-05-19Henrik Grubbström (Grubba)  if (u) { *u = 0; /* Unique rows in array b */ }
088e2e1998-02-12Mirar (Pontus Hagland)  map=allocate_mapping(256); push_mapping(map); /* in case of out of memory */ for (i=0; i<b->size; i++) { pval=low_mapping_lookup(map,b->item+i); if (!pval) { struct svalue val; val.type=T_ARRAY; val.u.array=low_allocate_array(1,1);
2523ce2003-04-28Martin Stjernholm  ITEM(val.u.array)[0].u.integer=i; val.u.array->type_field = BIT_INT; mapping_insert(map,ITEM(b)+i,&val);
088e2e1998-02-12Mirar (Pontus Hagland)  free_svalue(&val);
f873831998-05-19Henrik Grubbström (Grubba)  if (u) { (*u)++; }
088e2e1998-02-12Mirar (Pontus Hagland)  } else { pval->u.array=resize_array(pval->u.array,pval->u.array->size+1); pval->u.array->item[pval->u.array->size-1].type=T_INT; pval->u.array->item[pval->u.array->size-1].subtype=NUMBER_NUMBER; pval->u.array->item[pval->u.array->size-1].u.integer=i; } } res=low_allocate_array(a->size,0);
2523ce2003-04-28Martin Stjernholm  types = 0;
088e2e1998-02-12Mirar (Pontus Hagland)  for (i=0; i<a->size; i++) { pval=low_mapping_lookup(map,a->item+i); if (!pval) {
2523ce2003-04-28Martin Stjernholm  ITEM(res)[i].type=T_ARRAY; add_ref(ITEM(res)[i].u.array=&empty_array); types |= BIT_ARRAY;
088e2e1998-02-12Mirar (Pontus Hagland)  } else {
2523ce2003-04-28Martin Stjernholm  assign_svalue(ITEM(res)+i,pval); types |= 1 << ITEM(res)[i].type;
088e2e1998-02-12Mirar (Pontus Hagland)  } }
2523ce2003-04-28Martin Stjernholm  res->type_field = types;
088e2e1998-02-12Mirar (Pontus Hagland)  pop_stack(); return res; }
7083e31998-02-15Mirar (Pontus Hagland) struct diff_magic_link { int x; int refs; struct diff_magic_link *prev; }; struct diff_magic_link_pool { struct diff_magic_link *firstfree; struct diff_magic_link_pool *next; int firstfreenum; struct diff_magic_link dml[1]; };
f873831998-05-19Henrik Grubbström (Grubba) struct diff_magic_link_head { unsigned int depth; struct diff_magic_link *link; };
7083e31998-02-15Mirar (Pontus Hagland) #define DMLPOOLSIZE 16384 static int dmls=0; static INLINE struct diff_magic_link_pool* dml_new_pool(struct diff_magic_link_pool **pools) { struct diff_magic_link_pool *new;
088e2e1998-02-12Mirar (Pontus Hagland) 
7083e31998-02-15Mirar (Pontus Hagland)  new=malloc(sizeof(struct diff_magic_link_pool)+ sizeof(struct diff_magic_link)*DMLPOOLSIZE); if (!new) return NULL; /* fail */ new->firstfreenum=0; new->firstfree=NULL; new->next=*pools; *pools=new; return *pools; } static INLINE struct diff_magic_link* dml_new(struct diff_magic_link_pool **pools) { struct diff_magic_link *new; struct diff_magic_link_pool *pool; dmls++; if ( *pools && (new=(*pools)->firstfree) ) { (*pools)->firstfree=new->prev; new->prev=NULL; return new; } pool=*pools; while (pool) { if (pool->firstfreenum<DMLPOOLSIZE) return pool->dml+(pool->firstfreenum++); pool=pool->next; } if ( (pool=dml_new_pool(pools)) ) { pool->firstfreenum=1; return pool->dml; } return NULL; } static INLINE void dml_free_pools(struct diff_magic_link_pool *pools) { struct diff_magic_link_pool *pool; while (pools) { pool=pools->next; free(pools); pools=pool; } } static INLINE void dml_delete(struct diff_magic_link_pool *pools, struct diff_magic_link *dml) {
4062802001-09-27Fredrik Hübinette (Hubbe)  struct diff_magic_link *prev; while(1) { prev=dml->prev; dmls--; dml->prev=pools->firstfree; pools->firstfree=dml; if (prev && !--prev->refs) dml=prev; else break; }
7083e31998-02-15Mirar (Pontus Hagland) } static INLINE int diff_ponder_stack(int x, struct diff_magic_link **dml, int top) { int middle,a,b; a=0; b=top; while (b>a) { middle=(a+b)/2; if (dml[middle]->x<x) a=middle+1; else if (dml[middle]->x>x) b=middle; else return middle; } if (a<top && dml[a]->x<x) a++; return a; } static INLINE int diff_ponder_array(int x, struct svalue *arr, int top)
088e2e1998-02-12Mirar (Pontus Hagland) { int middle,a,b; a=0; b=top; while (b>a) { middle=(a+b)/2;
7083e31998-02-15Mirar (Pontus Hagland)  if (arr[middle].u.integer<x) a=middle+1; else if (arr[middle].u.integer>x) b=middle;
088e2e1998-02-12Mirar (Pontus Hagland)  else return middle; }
7083e31998-02-15Mirar (Pontus Hagland)  if (a<top && arr[a].u.integer<x) a++;
088e2e1998-02-12Mirar (Pontus Hagland)  return a; }
69faad1998-03-16Henrik Grubbström (Grubba) /* * The Grubba-Mirar Longest Common Sequence algorithm. * * This algorithm is O((Na * Nb / K)*lg(Na * Nb / K)), where: * * Na == sizeof(a) * Nb == sizeof(b) * K == sizeof(correlation(a,b)) * * For binary data: * K == 256 => O(Na * Nb * lg(Na * Nb)), * Na ~= Nb ~= N => O(N² * lg(N)) * * For ascii data: * K ~= C * min(Na, Nb), C constant => O(max(Na, Nb)*lg(max(Na,Nb))), * Na ~= Nb ~= N => O(N * lg(N)) * * diff_longest_sequence() takes two arguments: * cmptbl == diff_compare_table(a, b) * blen == sizeof(b) >= max(@(cmptbl*({}))) */
f873831998-05-19Henrik Grubbström (Grubba) static struct array *diff_longest_sequence(struct array *cmptbl, int blen)
088e2e1998-02-12Mirar (Pontus Hagland) {
9ca13e2003-06-12Martin Nilsson  int i,j,top=0;
088e2e1998-02-12Mirar (Pontus Hagland)  struct array *a;
7083e31998-02-15Mirar (Pontus Hagland)  struct diff_magic_link_pool *pools=NULL; struct diff_magic_link *dml; struct diff_magic_link **stack;
7be6851998-02-24Henrik Grubbström (Grubba)  char *marks;
088e2e1998-02-12Mirar (Pontus Hagland) 
c055781999-05-11Fredrik Hübinette (Hubbe)  if(!cmptbl->size) return allocate_array(0);
69faad1998-03-16Henrik Grubbström (Grubba)  stack = malloc(sizeof(struct diff_magic_link*)*cmptbl->size);
088e2e1998-02-12Mirar (Pontus Hagland) 
54db6c1999-03-27Henrik Grubbström (Grubba)  if (!stack) { int args = 0; SIMPLE_OUT_OF_MEMORY_ERROR("diff_longest_sequence", (int)sizeof(struct diff_magic_link*) * cmptbl->size); }
088e2e1998-02-12Mirar (Pontus Hagland) 
69faad1998-03-16Henrik Grubbström (Grubba)  /* NB: marks is used for optimization purposes only */
54db6c1999-03-27Henrik Grubbström (Grubba)  marks = calloc(blen, 1);
7be6851998-02-24Henrik Grubbström (Grubba) 
c055781999-05-11Fredrik Hübinette (Hubbe)  if (!marks && blen) {
54db6c1999-03-27Henrik Grubbström (Grubba)  int args = 0;
7be6851998-02-24Henrik Grubbström (Grubba)  free(stack);
54db6c1999-03-27Henrik Grubbström (Grubba)  SIMPLE_OUT_OF_MEMORY_ERROR("diff_longest_sequence", blen);
7be6851998-02-24Henrik Grubbström (Grubba)  }
69faad1998-03-16Henrik Grubbström (Grubba) #ifdef DIFF_DEBUG fprintf(stderr, "\n\nDIFF: sizeof(cmptbl)=%d, blen=%d\n", cmptbl->size, blen); #endif /* DIFF_DEBUG */ for (i = 0; i<cmptbl->size; i++)
7083e31998-02-15Mirar (Pontus Hagland)  { struct svalue *inner=cmptbl->item[i].u.array->item;
69faad1998-03-16Henrik Grubbström (Grubba) #ifdef DIFF_DEBUG fprintf(stderr, "DIFF: i=%d\n", i); #endif /* DIFF_DEBUG */ for (j = cmptbl->item[i].u.array->size; j--;)
088e2e1998-02-12Mirar (Pontus Hagland)  {
69faad1998-03-16Henrik Grubbström (Grubba)  int x = inner[j].u.integer;
7083e31998-02-15Mirar (Pontus Hagland) 
69faad1998-03-16Henrik Grubbström (Grubba) #ifdef DIFF_DEBUG fprintf(stderr, "DIFF: j=%d, x=%d\n", j, x); #endif /* DIFF_DEBUG */
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
978c1c1998-03-18Henrik Grubbström (Grubba)  if (x >= blen) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("diff_longest_sequence(): x:%d >= blen:%d\n", x, blen);
978c1c1998-03-18Henrik Grubbström (Grubba)  } else if (x < 0) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("diff_longest_sequence(): x:%d < 0\n", x);
978c1c1998-03-18Henrik Grubbström (Grubba)  }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #endif /* PIKE_DEBUG */
7be6851998-02-24Henrik Grubbström (Grubba)  if (!marks[x]) { int pos; if (top && x<=stack[top-1]->x) {
69faad1998-03-16Henrik Grubbström (Grubba)  /* Find the insertion point. */ pos = diff_ponder_stack(x, stack, top);
7be6851998-02-24Henrik Grubbström (Grubba)  if (pos != top) {
69faad1998-03-16Henrik Grubbström (Grubba)  /* Not on the stack anymore. */
7be6851998-02-24Henrik Grubbström (Grubba)  marks[stack[pos]->x] = 0; } } else pos=top;
69faad1998-03-16Henrik Grubbström (Grubba) #ifdef DIFF_DEBUG fprintf(stderr, "DIFF: pos=%d\n", pos); #endif /* DIFF_DEBUG */ /* This part is only optimization (j accelleration). */
7be6851998-02-24Henrik Grubbström (Grubba)  if (pos && j) { if (!marks[inner[j-1].u.integer]) {
69faad1998-03-16Henrik Grubbström (Grubba)  /* Find the element to insert. */ j = diff_ponder_array(stack[pos-1]->x+1, inner, j); x = inner[j].u.integer;
7be6851998-02-24Henrik Grubbström (Grubba)  } } else {
69faad1998-03-16Henrik Grubbström (Grubba)  j = 0; x = inner->u.integer;
7be6851998-02-24Henrik Grubbström (Grubba)  }
69faad1998-03-16Henrik Grubbström (Grubba)  #ifdef DIFF_DEBUG fprintf(stderr, "DIFF: New j=%d, x=%d\n", j, x); #endif /* DIFF_DEBUG */
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
978c1c1998-03-18Henrik Grubbström (Grubba)  if (x >= blen) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("diff_longest_sequence(): x:%d >= blen:%d\n", x, blen);
978c1c1998-03-18Henrik Grubbström (Grubba)  } else if (x < 0) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("diff_longest_sequence(): x:%d < 0\n", x);
978c1c1998-03-18Henrik Grubbström (Grubba)  }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #endif /* PIKE_DEBUG */
69faad1998-03-16Henrik Grubbström (Grubba)  /* Put x on the stack. */
7be6851998-02-24Henrik Grubbström (Grubba)  marks[x] = 1;
69faad1998-03-16Henrik Grubbström (Grubba)  if (pos == top)
7be6851998-02-24Henrik Grubbström (Grubba)  {
69faad1998-03-16Henrik Grubbström (Grubba) #ifdef DIFF_DEBUG fprintf(stderr, "DIFF: New top element\n"); #endif /* DIFF_DEBUG */
7be6851998-02-24Henrik Grubbström (Grubba)  if (! (dml=dml_new(&pools)) ) {
54db6c1999-03-27Henrik Grubbström (Grubba)  int args = 0;
7083e31998-02-15Mirar (Pontus Hagland)  dml_free_pools(pools); free(stack);
54db6c1999-03-27Henrik Grubbström (Grubba)  SIMPLE_OUT_OF_MEMORY_ERROR("diff_longest_sequence", sizeof(struct diff_magic_link_pool) + sizeof(struct diff_magic_link) * DMLPOOLSIZE);
7be6851998-02-24Henrik Grubbström (Grubba)  }
7083e31998-02-15Mirar (Pontus Hagland) 
69faad1998-03-16Henrik Grubbström (Grubba)  dml->x = x; dml->refs = 1;
7083e31998-02-15Mirar (Pontus Hagland) 
7be6851998-02-24Henrik Grubbström (Grubba)  if (pos)
f873831998-05-19Henrik Grubbström (Grubba)  (dml->prev = stack[pos-1])->refs++;
7be6851998-02-24Henrik Grubbström (Grubba)  else
69faad1998-03-16Henrik Grubbström (Grubba)  dml->prev = NULL;
7083e31998-02-15Mirar (Pontus Hagland) 
7be6851998-02-24Henrik Grubbström (Grubba)  top++;
7083e31998-02-15Mirar (Pontus Hagland) 
69faad1998-03-16Henrik Grubbström (Grubba)  stack[pos] = dml; } else if (pos && stack[pos]->refs == 1 && stack[pos-1] == stack[pos]->prev) { #ifdef DIFF_DEBUG fprintf(stderr, "DIFF: Optimized case\n"); #endif /* DIFF_DEBUG */ /* Optimization. */ stack[pos]->x = x; } else { #ifdef DIFF_DEBUG fprintf(stderr, "DIFF: Generic case\n"); #endif /* DIFF_DEBUG */ if (! (dml=dml_new(&pools)) )
7be6851998-02-24Henrik Grubbström (Grubba)  {
54db6c1999-03-27Henrik Grubbström (Grubba)  int args = 0;
69faad1998-03-16Henrik Grubbström (Grubba)  dml_free_pools(pools); free(stack);
54db6c1999-03-27Henrik Grubbström (Grubba)  SIMPLE_OUT_OF_MEMORY_ERROR("diff_longest_sequence", sizeof(struct diff_magic_link_pool) + sizeof(struct diff_magic_link) * DMLPOOLSIZE);
7be6851998-02-24Henrik Grubbström (Grubba)  }
69faad1998-03-16Henrik Grubbström (Grubba)  dml->x = x; dml->refs = 1; if (pos)
f873831998-05-19Henrik Grubbström (Grubba)  (dml->prev = stack[pos-1])->refs++;
7be6851998-02-24Henrik Grubbström (Grubba)  else
69faad1998-03-16Henrik Grubbström (Grubba)  dml->prev = NULL; if (!--stack[pos]->refs) dml_delete(pools, stack[pos]);
7083e31998-02-15Mirar (Pontus Hagland) 
69faad1998-03-16Henrik Grubbström (Grubba)  stack[pos] = dml; } #ifdef DIFF_DEBUG } else { fprintf(stderr, "DIFF: Already marked (%d)!\n", marks[x]); #endif /* DIFF_DEBUG */
7be6851998-02-24Henrik Grubbström (Grubba)  }
088e2e1998-02-12Mirar (Pontus Hagland)  }
69faad1998-03-16Henrik Grubbström (Grubba) #ifdef DIFF_DEBUG for(j=0; j < top; j++) { fprintf(stderr, "DIFF: stack:%d, mark:%d\n", stack[j]->x, marks[stack[j]->x]); } #endif /* DIFF_DEBUG */
7083e31998-02-15Mirar (Pontus Hagland)  }
088e2e1998-02-12Mirar (Pontus Hagland) 
7be6851998-02-24Henrik Grubbström (Grubba)  /* No need for marks anymore. */ free(marks);
a4a1722000-12-05Per Hedbor  /* FIXME(?) memory unfreed upon error here. */
088e2e1998-02-12Mirar (Pontus Hagland)  a=low_allocate_array(top,0);
7083e31998-02-15Mirar (Pontus Hagland)  if (top)
088e2e1998-02-12Mirar (Pontus Hagland)  {
7083e31998-02-15Mirar (Pontus Hagland)  dml=stack[top-1]; while (dml) {
2523ce2003-04-28Martin Stjernholm  ITEM(a)[--top].u.integer=dml->x;
7083e31998-02-15Mirar (Pontus Hagland)  dml=dml->prev; }
2523ce2003-04-28Martin Stjernholm  a->type_field = BIT_INT;
088e2e1998-02-12Mirar (Pontus Hagland)  } free(stack);
7083e31998-02-15Mirar (Pontus Hagland)  dml_free_pools(pools);
088e2e1998-02-12Mirar (Pontus Hagland)  return a; }
f873831998-05-19Henrik Grubbström (Grubba) /* * The dynamic programming Longest Common Sequence algorithm. * * This algorithm is O(Na * Nb), where: * * Na == sizeof(a) * Nb == sizeof(b) * * This makes it faster than the G-M algorithm on binary data, * but slower on ascii data.
c337d91998-05-19Henrik Grubbström (Grubba)  * * NOT true! The G-M algorithm seems to be faster on most data anyway. * /grubba 1998-05-19
f873831998-05-19Henrik Grubbström (Grubba)  */
bde0ef1998-05-19Henrik Grubbström (Grubba) static struct array *diff_dyn_longest_sequence(struct array *cmptbl, int blen)
f873831998-05-19Henrik Grubbström (Grubba) { struct array *res = NULL;
9ca13e2003-06-12Martin Nilsson  struct diff_magic_link_head *table;
f873831998-05-19Henrik Grubbström (Grubba)  struct diff_magic_link_pool *dml_pool = NULL; struct diff_magic_link *dml;
bde0ef1998-05-19Henrik Grubbström (Grubba)  unsigned int sz = (unsigned int)cmptbl->size; unsigned int i;
f873831998-05-19Henrik Grubbström (Grubba)  unsigned int off1 = 0;
bde0ef1998-05-19Henrik Grubbström (Grubba)  unsigned