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. */
aedfb12002-10-09Martin Nilsson 
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "global.h" #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"
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 "opcodes.h"
fc33451997-10-02Fredrik Hübinette (Hubbe) #include "cyclic.h"
89b0721998-05-05Fredrik Hübinette (Hubbe) #include "signal_handler.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"
e021fe2008-04-14Henrik Grubbström (Grubba) #include "pike_compiler.h"
e0f6ba2016-03-06Martin Nilsson #include "port.h"
7419c22016-07-03Arne Goedeke #include "siphash24.h"
6930181996-02-25Fredrik Hübinette (Hubbe) 
1abad82011-07-01Martin Stjernholm #include <errno.h>
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) *!
51eb172015-05-14Henrik Grubbström (Grubba)  *! This function checks if the values @[a] and @[b] are equivalent.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
51eb172015-05-14Henrik Grubbström (Grubba)  *! @returns *! If either of the values is an object the (normalized) result *! of calling @[lfun::_equal()] will be returned. *! *! Returns @expr{1@} if both values are false (zero, destructed objects, *! prototype functions, etc). *! *! Returns @expr{0@} (zero) if the values have different types. *! *! Otherwise depending on the type of the values: *! @mixed *! @type int *! @type float *! @type string *! @type program *! Returns the same as @expr{a == b@}. *! @type array *! @type mapping *! @type multiset *! @type object *! The contents of @[a] and @[b] are checked recursively, and *! if all their contents are @[equal] and in the same place, *! they are considered equal. *! *! Note that for objects this case is only reached if neither *! @[a] nor @[b] implements @[lfun::_equal()]. *! @type type *! Returns @expr{(a <= b) && (b <= a)@}. *! @endmixed
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
7e17992015-06-17Henrik 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)
06bd612016-01-26Martin Nilsson  SIMPLE_WRONG_NUM_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 */ }
faafc52005-03-16Henrik Grubbström (Grubba) static node *optimize_f_aggregate(node *n) { /* Split long argument lists into multiple function calls. * * aggregate(...) ==> `+(aggregate(...arg32), aggregate(arg33...), ...) * * Also removes splices. * * Note: We assume that the argument list is in left-recursive form. */ node *args = CDR(n); node *new_args = NULL; node *add_args = NULL; int count; if (!args) return NULL; args->parent = NULL; for (count = 0; args->token == F_ARG_LIST; args = CAR(args)) { if (CDR(args) && CDR(args)->token == F_PUSH_ARRAY) { /* Splices have a weight of 16. */ count += 16; } else { count++; } if (!CAR(args)) break; CAR(args)->parent = args; } if (args->token == F_PUSH_ARRAY) { /* Last argument is a splice */ count += 16; } else if (args->token != F_ARG_LIST) { count++; } /* Ignore cases with 32 or less arguments. */ if (count <= 32) { CDR(n)->parent = n; return NULL; } /* * Perform the actual rewrite. * * Start with the last arg, and work towards the first. */ count = 0; if (args->token != F_ARG_LIST) { if (args->token == F_PUSH_ARRAY) { /* Splice operator. */ add_args = copy_node(CAR(args)); } else { new_args = copy_node(args); count = 1; } args = args->parent; } for(; args; args = args->parent) {
594f162007-01-15Henrik Grubbström (Grubba)  if (!CDR(args)) continue;
faafc52005-03-16Henrik Grubbström (Grubba)  if (CDR(args)->token == F_PUSH_ARRAY) { if (count) { add_args = mknode(F_ARG_LIST, add_args, mkapplynode(copy_node(CAR(n)), new_args)); new_args = NULL; count = 0; } add_args = mknode(F_ARG_LIST, add_args, copy_node(CADR(args))); } else { new_args = mknode(F_ARG_LIST, new_args, copy_node(CDR(args))); count++; if (count > 31) { add_args = mknode(F_ARG_LIST, add_args, mkapplynode(copy_node(CAR(n)), new_args)); new_args = NULL; count = 0; } } } if (count) { add_args = mknode(F_ARG_LIST, add_args, mkapplynode(copy_node(CAR(n)), new_args)); new_args = NULL; count = 0; } CDR(n)->parent = n; return mkefuncallnode("`+", add_args); }
0811472001-07-02Fredrik Hübinette (Hubbe) 
1b068a2011-05-15Per Hedbor #define MK_HASHMEM(NAME, TYPE) ATTRIBUTE((const)) \
01b9212016-01-12Per Hedbor  static inline size_t NAME(const TYPE *str, ptrdiff_t len, ptrdiff_t maxn) \
1b068a2011-05-15Per Hedbor  { \ size_t ret,c; \ \ ret = len*92873743; \ \ len = MINIMUM(maxn,len); \ for(; len>=0; len--) \ { \ c=str++[0]; \ ret ^= ( ret << 4 ) + c ; \ ret &= 0x7fffffff; \ } \ return ret; \ } MK_HASHMEM(simple_hashmem, unsigned char) MK_HASHMEM(simple_hashmem1, p_wchar1) MK_HASHMEM(simple_hashmem2, p_wchar2)
f6c5cf2014-12-06Henrik Grubbström (Grubba) /*! @decl int hash_7_4(string s) *! @decl int hash_7_4(string s, int max)
5d98c42003-03-02Henrik Grubbström (Grubba)  *!
5ad0962003-11-10Martin Stjernholm  *! Return an integer derived from the string @[s]. The same string
c3bc8f2015-06-17Henrik Grubbström (Grubba)  *! always hashes to the same value, also between processes.
1a3aec2014-11-24Stephen R. van den Berg  *! *! If @[max] is given, the result will be >= 0 and < @[max], *! otherwise the result will be >= 0 and <= 0x7fffffff. *! *! @note
c3bc8f2015-06-17Henrik Grubbström (Grubba)  *! This function is provided for backward compatibility with *! code written for Pike up and including version 7.4.
1a3aec2014-11-24Stephen R. van den Berg  *! *! This function is byte-order dependant for wide strings. *! *! @seealso
93f1842016-06-24Per Hedbor  *! @[hash_7_6()], @[hash_7_0]
1a3aec2014-11-24Stephen R. van den Berg  */ static void f_hash_7_4(INT32 args) { size_t i = 0; struct pike_string *s = Pike_sp[-args].u.string; if(!args)
06bd612016-01-26Martin Nilsson  SIMPLE_WRONG_NUM_ARGS_ERROR("7.4::hash",1);
1a3aec2014-11-24Stephen R. van den Berg  if(TYPEOF(Pike_sp[-args]) != T_STRING)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("7.4::hash", 1, "string");
1a3aec2014-11-24Stephen R. van den Berg  i = simple_hashmem((unsigned char *)s->str, s->len<<s->size_shift, 100<<s->size_shift); if(args > 1) { if(TYPEOF(Pike_sp[1-args]) != T_INT)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("7.4::hash",2,"int");
1a3aec2014-11-24Stephen R. van den Berg  if(!Pike_sp[1-args].u.integer) PIKE_ERROR("7.4::hash", "Modulo by zero.\n", Pike_sp, args); i%=(unsigned INT32)Pike_sp[1-args].u.integer; } pop_n_elems(args); push_int64(i); }
01b9212016-01-12Per Hedbor ATTRIBUTE((const)) static inline size_t hashstr(const unsigned char *str, ptrdiff_t maxn)
1a3aec2014-11-24Stephen R. van den Berg { size_t ret,c; if(!(ret=str++[0])) return ret; for(; maxn>=0; maxn--) { c=str++[0]; if(!c) break; ret ^= ( ret << 4 ) + c ; ret &= 0x7fffffff; } return ret; } /*! @decl int hash_7_0(string s) *! @decl int hash_7_0(string s, int max) *! *! 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. *! *! @note *! This function is provided for backward compatibility with *! code written for Pike up and including version 7.0. *! *! This function is not NUL-safe, and is byte-order dependant. *! *! @seealso
39073b2014-11-24Martin Nilsson  *! @[hash()], @[hash_7_4]
1a3aec2014-11-24Stephen R. van den Berg  */ static void f_hash_7_0( INT32 args ) { struct pike_string *s = Pike_sp[-args].u.string; unsigned int i; if(!args)
06bd612016-01-26Martin Nilsson  SIMPLE_WRONG_NUM_ARGS_ERROR("7.0::hash",1);
1a3aec2014-11-24Stephen R. van den Berg  if(TYPEOF(Pike_sp[-args]) != T_STRING)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("7.0::hash", 1, "string");
1a3aec2014-11-24Stephen R. van den Berg  if( s->size_shift ) { f_hash_7_4( args ); return; }
bd67392015-10-14Martin Nilsson  i = (unsigned int)hashstr( (unsigned char *)s->str, MINIMUM(100,s->len));
1a3aec2014-11-24Stephen R. van den Berg  if(args > 1) { if(TYPEOF(Pike_sp[1-args]) != T_INT)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("7.0::hash",2,"int");
1a3aec2014-11-24Stephen R. van den Berg  if(!Pike_sp[1-args].u.integer) PIKE_ERROR("7.0::hash", "Modulo by zero.\n", Pike_sp, args); i%=(unsigned INT32)Pike_sp[1-args].u.integer; } pop_n_elems(args); push_int( i ); }
b7de1a2016-07-02Henrik Grubbström (Grubba) /*! @decl int hash_8_0(string s) *! @decl int hash_8_0(string s, int max)
1a3aec2014-11-24Stephen R. van den Berg  *! *! Return an integer derived from the string @[s]. The same string
5ad0962003-11-10Martin Stjernholm  *! 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)  *!
93f1842016-06-24Per Hedbor  *! @deprecated *! *! Use @[hash_value()] for in-process hashing (eg, for implementing *! @[lfun::_hash()]) or one of the cryptographic hash functions. *! *! @note *! This function is really bad at hashing strings. Similar string *! often return similar hash values. *! *! It is especially bad for url:s, paths and similarly formatted *! strings. *!
ce4d672001-01-31Henrik Grubbström (Grubba)  *! @note
1a3aec2014-11-24Stephen R. van den Berg  *! The hash algorithm was changed in Pike 7.5. If you want a hash
c3bc8f2015-06-17Henrik Grubbström (Grubba)  *! that is compatible with Pike 7.4 and earlier, use @[hash_7_4()].
1a3aec2014-11-24Stephen R. van den Berg  *! The difference only affects wide strings. *! *! The hash algorithm was also changed in Pike 7.1. If you want a hash
c3bc8f2015-06-17Henrik Grubbström (Grubba)  *! that is compatible with Pike 7.0 and earlier, use @[hash_7_0()].
1a3aec2014-11-24Stephen R. van den Berg  *! *! @note
e751c42010-05-19Henrik Grubbström (Grubba)  *! This hash function differs from the one provided by @[hash_value()], *! in that @[hash_value()] returns a process specific value. *!
ce4d672001-01-31Henrik Grubbström (Grubba)  *! @seealso
b7de1a2016-07-02Henrik Grubbström (Grubba)  *! @[hash()], @[hash_7_0()], @[hash_7_4()], @[hash_value]
ce4d672001-01-31Henrik Grubbström (Grubba)  */
7a2f402016-11-05Martin Nilsson static void f_hash_8_0(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)
06bd612016-01-26Martin Nilsson  SIMPLE_WRONG_NUM_ARGS_ERROR("hash",1);
98d8e72000-12-10Per Hedbor 
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[-args]) != T_STRING)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_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; }
98d8e72000-12-10Per Hedbor 
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(args > 1) {
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[1-args]) != T_INT)
b7de1a2016-07-02Henrik Grubbström (Grubba)  SIMPLE_ARG_TYPE_ERROR("hash_8_0",2,"int");
1a3aec2014-11-24Stephen R. van den Berg 
c5ab042004-05-13Martin Nilsson  if(Pike_sp[1-args].u.integer <= 0)
b7de1a2016-07-02Henrik Grubbström (Grubba)  PIKE_ERROR("hash_8_0", "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) }
1565da2016-06-29Henrik Grubbström (Grubba) /*! @decl int hash(string s) *! @decl int hash(string s, int max) *! *! 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. *! *! @note *! The hash algorithm was changed in Pike 8.1. If you want a hash
b7de1a2016-07-02Henrik Grubbström (Grubba)  *! that is compatible with Pike 8.0 and earlier, use @[hash_8_0()].
1565da2016-06-29Henrik Grubbström (Grubba)  *! *! The hash algorithm was also changed in Pike 7.5. If you want a hash *! that is compatible with Pike 7.4 and earlier, use @[hash_7_4()]. *! The difference with regards to @[hash_8_0()] only affects wide strings. *! *! The hash algorithm was also changed in Pike 7.1. If you want a hash *! that is compatible with Pike 7.0 and earlier, use @[hash_7_0()]. *! *! @note *! This hash function differs from the one provided by @[hash_value()], *! in that @[hash_value()] returns a process specific value. *! *! @seealso
b7de1a2016-07-02Henrik Grubbström (Grubba)  *! @[hash_7_0()], @[hash_7_4()], @[hash_8_0()], @[hash_value]
1565da2016-06-29Henrik Grubbström (Grubba)  */
7a2f402016-11-05Martin Nilsson PMOD_EXPORT void f_hash( INT32 args )
5691892016-06-24Per Hedbor {
1565da2016-06-29Henrik Grubbström (Grubba)  size_t res;
5691892016-06-24Per Hedbor  if( TYPEOF(Pike_sp[-args]) != PIKE_T_STRING ) PIKE_ERROR("hash","Argument is not a string\n",Pike_sp,args);
1565da2016-06-29Henrik Grubbström (Grubba) 
7419c22016-07-03Arne Goedeke  res = pike_string_siphash24(Pike_sp[-args].u.string, 0) & 0x7fffffff;
1565da2016-06-29Henrik Grubbström (Grubba)  if( args > 1 ) { if(TYPEOF(Pike_sp[1-args]) != T_INT) SIMPLE_ARG_TYPE_ERROR("hash",2,"int"); if(Pike_sp[1-args].u.integer <= 0) PIKE_ERROR("hash", "Modulo < 1.\n", Pike_sp, args); res %= Pike_sp[1-args].u.integer; } pop_n_elems(args); push_int(res);
5691892016-06-24Per Hedbor }
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
e751c42010-05-19Henrik Grubbström (Grubba)  *! is called and its result returned.
5ad0962003-11-10Martin Stjernholm  *! *! @note
e751c42010-05-19Henrik Grubbström (Grubba)  *! This is the hashing method used by mappings.
5ad0962003-11-10Martin Stjernholm  *! *! @seealso
93f1842016-06-24Per Hedbor  *! @[lfun::__hash()]
5ad0962003-11-10Martin Stjernholm  */ void f_hash_value(INT32 args) {
51c88e2016-08-18Henrik Grubbström (Grubba)  size_t h;
5ad0962003-11-10Martin Stjernholm  if(!args)
06bd612016-01-26Martin Nilsson  SIMPLE_WRONG_NUM_ARGS_ERROR("hash_value",1);
5ad0962003-11-10Martin Stjernholm  h = hash_svalue (Pike_sp - args); pop_n_elems (args);
51c88e2016-08-18Henrik Grubbström (Grubba)  /* NB: We assume that INT_TYPE has the same width as size_t. */
5ad0962003-11-10Martin Stjernholm  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)
06bd612016-01-26Martin Nilsson  SIMPLE_WRONG_NUM_ARGS_ERROR("copy_value",1);
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args-1);
c2464e2009-08-26Henrik Grubbström (Grubba)  push_undefined(); /* Placeholder */
cada522009-08-26Martin Stjernholm  copy_svalues_recursively_no_free(Pike_sp-1,Pike_sp-2,1,0); free_svalue(Pike_sp-2); move_svalue (Pike_sp - 2, Pike_sp - 1); Pike_sp--;
edf4d02000-07-06Fredrik Hübinette (Hubbe)  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. */
8fe0e42005-05-08Martin Nilsson  INT16 mode; INT16 data;
94d9921999-03-20Henrik Grubbström (Grubba) };
002bd52008-05-29Martin Nilsson #define CIM_NONE 0 /* Case-less */ #define CIM_UPPERDELTA 1 /* Upper-case, delta to lower-case in data */ #define CIM_LOWERDELTA 2 /* Lower-case, -delta to upper-case in data */ #define CIM_CASEBIT 3 /* Some case, case mask in data */ #define CIM_CASEBITOFF 4 /* Same as above, but also offset by data */ #define CIM_LONGUPPERDELTA 5 /* Upper-case, delta + 0x7fff. */ #define CIM_LONGLOWERDELTA 6 /* Lower-case, delta + 0x7fff. */
94d9921999-03-20Henrik Grubbström (Grubba) 
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)) {
13670c2015-05-25Martin Nilsson  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)) {
13670c2015-05-25Martin Nilsson  return ci;
480bf02000-07-27Andreas Lange  } 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; \
002bd52008-05-29Martin Nilsson  if(c<0xb5){if(c >= 'A' && c <= 'Z' ) C=c+0x20; } \ /*else if(c==0xa77d) C=0x1d79;*/ else { \
3325952004-04-13Jonas Wallden  struct case_info *ci = find_ci(c); \
94d9921999-03-20Henrik Grubbström (Grubba)  if (ci) { \ switch(ci->mode) { \
002bd52008-05-29Martin Nilsson  case CIM_NONE: case CIM_LOWERDELTA: case CIM_LONGLOWERDELTA: break; \
164d671999-03-20Henrik Grubbström (Grubba)  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; \
002bd52008-05-29Martin Nilsson  case CIM_LONGUPPERDELTA: \ C = c + ci->data + ( ci->data>0 ? 0x7fff : -0x8000 ); break; \
c6b6042008-05-03Martin Nilsson  DO_IF_DEBUG( 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; \
03c75f2004-10-14Martin Nilsson  if(c<0xb5){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; \
c6b6042008-05-03Martin Nilsson  DO_IF_DEBUG( 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; \
002bd52008-05-29Martin Nilsson  if(c<0xb5){if(c >= 'a' && c <= 'z' ) C=c-0x20; } \ /*else if(c==0x1d79) C=0xa77d;*/ else {\
94d9921999-03-20Henrik Grubbström (Grubba)  struct case_info *ci = find_ci(c); \ if (ci) { \ switch(ci->mode) { \
002bd52008-05-29Martin Nilsson  case CIM_NONE: case CIM_UPPERDELTA: case CIM_LONGUPPERDELTA: break; \
164d671999-03-20Henrik Grubbström (Grubba)  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; \
002bd52008-05-29Martin Nilsson  case CIM_LONGLOWERDELTA: \ C = c - ci->data - ( ci->data>0 ? 0x7fff : -0x8000 ); break; \
c6b6042008-05-03Martin Nilsson  DO_IF_DEBUG( 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; \
03c75f2004-10-14Martin Nilsson  if(c<0xb5){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; \
c6b6042008-05-03Martin Nilsson  DO_IF_DEBUG( 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
0b8d2f2013-06-17Martin Nilsson  *! ISO-10646 (aka Unicode). If they are not, @[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
0b8d2f2013-06-17Martin Nilsson  *! @[upper_case()], @[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);
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-args]) == T_INT) {
6f18562003-09-05Henrik Grubbström (Grubba)  /* NOTE: Performs the case change in place. */ DO_LOWER_CASE(Pike_sp[-args].u.integer); pop_n_elems(args-1); return; }
9925512013-05-31Per Hedbor 
c5ab042004-05-13Martin Nilsson  orig = Pike_sp[-args].u.string;
9925512013-05-31Per Hedbor  if( orig->flags & STRING_IS_LOWERCASE ) return;
94d9921999-03-20Henrik Grubbström (Grubba)  ret = begin_wide_shared_string(orig->len, orig->size_shift);
59fc9e2014-09-03Martin Nilsson  memcpy(ret->str, orig->str, orig->len << orig->size_shift);
94d9921999-03-20Henrik Grubbström (Grubba)  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]); }
c6b6042008-05-03Martin Nilsson #ifdef PIKE_DEBUG
94d9921999-03-20Henrik Grubbström (Grubba)  } else {
5aad932002-08-15Marcus Comstedt  Pike_fatal("lower_case(): Bad string shift:%d\n", orig->size_shift);
c6b6042008-05-03Martin Nilsson #endif
94d9921999-03-20Henrik Grubbström (Grubba)  }
5267b71995-08-09Fredrik Hübinette (Hubbe) 
9925512013-05-31Per Hedbor  ret = end_shared_string(ret); ret->flags |= STRING_IS_LOWERCASE;
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args);
9925512013-05-31Per Hedbor  push_string(ret);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
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
0b8d2f2013-06-17Martin Nilsson  *! ISO-10646 (aka Unicode). If they are not, @[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
0b8d2f2013-06-17Martin Nilsson  *! @[lower_case()], @[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);
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-args]) == T_INT) {
6f18562003-09-05Henrik Grubbström (Grubba)  /* NOTE: Performs the case change in place. */ DO_UPPER_CASE(Pike_sp[-args].u.integer); pop_n_elems(args-1); return; }
9925512013-05-31Per Hedbor 
c5ab042004-05-13Martin Nilsson  orig = Pike_sp[-args].u.string;
9925512013-05-31Per Hedbor  if( orig->flags & STRING_IS_UPPERCASE ) { return; }
5e3f721999-03-20Per Hedbor  ret=begin_wide_shared_string(orig->len,orig->size_shift);
59fc9e2014-09-03Martin Nilsson  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. */
fb22942008-06-16Martin Stjernholm  do_free_unlinked_pike_string(ret);
c5ab042004-05-13Martin Nilsson  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]); }
c6b6042008-05-03Martin Nilsson #ifdef PIKE_DEBUG
94d9921999-03-20Henrik Grubbström (Grubba)  } else {
5aad932002-08-15Marcus Comstedt  Pike_fatal("lower_case(): Bad string shift:%d\n", orig->size_shift);
c6b6042008-05-03Martin Nilsson #endif
94d9921999-03-20Henrik Grubbström (Grubba)  }
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args);
9925512013-05-31Per Hedbor  ret = end_shared_string(ret); ret->flags |= STRING_IS_UPPERCASE; push_string(ret);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
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()]
70532f2016-01-17Martin Nilsson  *! *! @deprecated *! @[Random.Deterministic]
9c1a7b2001-01-08Henrik Grubbström (Grubba)  */
6068372016-01-18Martin Nilsson static void f_random_seed(INT32 args)
cb22561995-10-11Fredrik Hübinette (Hubbe) {
8aefbc1999-03-19Fredrik Hübinette (Hubbe)  INT_TYPE 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) }
a52ec22017-02-15Henrik Grubbström (Grubba) /*! @decl int search(string haystack, string|int needle, int|void start, @ *! int|void end) *! @decl int search(array haystack, mixed needle, int|void start, int|void end)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! @decl mixed search(mapping haystack, mixed needle, mixed|void start)
8a76762016-10-12Henrik Grubbström (Grubba)  *! @decl mixed search(object haystack, mixed needle, mixed|void start, @ *! mixed ... extra_args)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
9972fa2016-10-11Henrik Grubbström (Grubba)  *! Search for @[needle] in @[haystack].
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
9972fa2016-10-11Henrik Grubbström (Grubba)  *! @param haystack *! Item to search in. This can be one of: *! @mixed
b5b59a2003-09-04Henrik Grubbström (Grubba)  *! @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
9972fa2016-10-11Henrik Grubbström (Grubba)  *! mapping backwards.
b5b59a2003-09-04Henrik Grubbström (Grubba)  *! *! @type object *! When @[haystack] is an object implementing @[lfun::_search()],
8a76762016-10-12Henrik Grubbström (Grubba)  *! the result of calling @[lfun::_search()] with @[needle], @[start] *! and any @[extra_args] will be returned.
b5b59a2003-09-04Henrik Grubbström (Grubba)  *! *! 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
9972fa2016-10-11Henrik Grubbström (Grubba)  *! found, @[haystack] will be advanced to the end. *! @endmixed *! *! @param start *! If the optional argument @[start] is present search is started at
2426132016-10-12Martin Nilsson  *! this position. This has no effect on mappings.
9972fa2016-10-11Henrik Grubbström (Grubba)  *!
a52ec22017-02-15Henrik Grubbström (Grubba)  *! @param end *! If the optional argument @[end] is present, the search will terminate
b7646b2017-04-02Henrik Grubbström (Grubba)  *! at this position (exclusive) if not found earlier.
a52ec22017-02-15Henrik Grubbström (Grubba)  *!
9972fa2016-10-11Henrik Grubbström (Grubba)  *! @returns *! Returns the position of @[needle] in @[haystack] if found. *! *! If not found the returned value depends on the type of @[haystack]: *! @mixed *! @type string|array *! @expr{-1@}. *! @type mapping|object(Iterator) *! @[UNDEFINED]. *! @type object *! The value returned by @[lfun::_search()].
b5b59a2003-09-04Henrik Grubbström (Grubba)  *! @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)  *!
594f162007-01-15Henrik Grubbström (Grubba)  *! @note *! For mappings and object @[UNDEFINED] will be returned when not found. *! In all other cases @expr{-1@} will be returned when not found. *!
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! @seealso
13670c2015-05-25Martin Nilsson  *! @[indices()], @[values()], @[zero_type()], @[has_value()],
38cb402010-03-30Peter Bortas  *! @[has_prefix()], @[has_suffix()]
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;
a52ec22017-02-15Henrik Grubbström (Grubba)  ptrdiff_t end;
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(args < 2)
06bd612016-01-26Martin Nilsson  SIMPLE_WRONG_NUM_ARGS_ERROR("search", 2);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
017b572011-10-28Henrik Grubbström (Grubba)  switch(TYPEOF(Pike_sp[-args]))
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;
a52ec22017-02-15Henrik Grubbström (Grubba)  end = haystack->len;
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(args > 2) {
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[2-args]) != T_INT)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_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) {
212c392018-02-25Martin Nilsson  bad_arg_error("search", args, 3, "int(0..)", Pike_sp+2-args,
d0d01b1999-03-20Henrik Grubbström (Grubba)  "Start must be greater or equal to zero.\n"); }
a52ec22017-02-15Henrik Grubbström (Grubba)  if (args > 3) { if(TYPEOF(Pike_sp[3-args]) != T_INT) SIMPLE_ARG_TYPE_ERROR("search", 4, "int"); if (Pike_sp[3-args].u.integer < end) { end = Pike_sp[3-args].u.integer; if(start<0) {
212c392018-02-25Martin Nilsson  bad_arg_error("search", args, 4, "int(0..)",
a52ec22017-02-15Henrik Grubbström (Grubba)  Pike_sp+3-args, "End must be greater or equal to zero.\n"); } } }
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
9cf6c82001-03-11Henrik Grubbström (Grubba)  if(haystack->len < start)
212c392018-02-25Martin Nilsson  bad_arg_error("search", 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) 
a52ec22017-02-15Henrik Grubbström (Grubba)  if (end <= start) { pop_n_elems(args); push_int(-1); return; }
017b572011-10-28Henrik Grubbström (Grubba)  if ((TYPEOF(Pike_sp[1-args]) == T_INT) || ((TYPEOF(Pike_sp[1-args]) == T_STRING) &&
f05e112009-09-09Henrik Grubbström (Grubba)  (Pike_sp[1-args].u.string->len == 1))) { INT_TYPE val;
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[1-args]) == T_INT) {
f05e112009-09-09Henrik Grubbström (Grubba)  val = Pike_sp[1-args].u.integer; } else { val = index_shared_string(Pike_sp[1-args].u.string, 0);
e38ce92001-10-30Henrik Grubbström (Grubba)  }
9925512013-05-31Per Hedbor  if( !string_range_contains( haystack, val ) ) { pop_n_elems(args); push_int( -1 ); return; }
9cf6c82001-03-11Henrik Grubbström (Grubba)  switch(Pike_sp[-args].u.string->size_shift) { case 0: { p_wchar0 *str = STR0(haystack); if (val >= 256) { start = -1; break; }
a52ec22017-02-15Henrik Grubbström (Grubba)  while (start < end) {
9cf6c82001-03-11Henrik Grubbström (Grubba)  if (str[start] == val) break; start++; } } break; case 1: { p_wchar1 *str = STR1(haystack); if (val >= 65536) { start = -1; break; }
a52ec22017-02-15Henrik Grubbström (Grubba)  while (start < end) {
9cf6c82001-03-11Henrik Grubbström (Grubba)  if (str[start] == val) break; start++; } } break; case 2: { p_wchar2 *str = STR2(haystack);
a52ec22017-02-15Henrik Grubbström (Grubba)  while (start < end) {
9cf6c82001-03-11Henrik Grubbström (Grubba)  if (str[start] == (p_wchar2)val) break; start++; } } break; }
017b572011-10-28Henrik Grubbström (Grubba)  } else if(TYPEOF(Pike_sp[1-args]) == T_STRING) {
f05e112009-09-09Henrik 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);
b7646b2017-04-02Henrik Grubbström (Grubba)  end -= Pike_sp[1-args].u.string->len-1;
f05e112009-09-09Henrik Grubbström (Grubba)  }
9cf6c82001-03-11Henrik Grubbström (Grubba)  } else {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("search", 2, "string | int");
9cf6c82001-03-11Henrik Grubbström (Grubba)  }
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args);
a52ec22017-02-15Henrik Grubbström (Grubba)  if (start >= end) { start = -1; }
93b7202000-08-14Henrik Grubbström (Grubba)  push_int64(start);
5267b71995-08-09Fredrik Hübinette (Hubbe)  break; } case T_ARRAY: start=0;
a52ec22017-02-15Henrik Grubbström (Grubba)  end = Pike_sp[-args].u.array->size;
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(args > 2) {
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[2-args]) != T_INT)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_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) {
212c392018-02-25Martin Nilsson  bad_arg_error("search", args, 3, "int(0..)", Pike_sp+2-args,
c2998a1999-11-08Henrik Grubbström (Grubba)  "Start must be greater or equal to zero.\n"); }
a52ec22017-02-15Henrik Grubbström (Grubba)  if (args > 3) { if(TYPEOF(Pike_sp[3-args]) != T_INT) SIMPLE_ARG_TYPE_ERROR("search", 4, "int"); if (Pike_sp[3-args].u.integer < end) { end = Pike_sp[3-args].u.integer; if(end<0) {
212c392018-02-25Martin Nilsson  bad_arg_error("search", args, 4, "int(0..)",
a52ec22017-02-15Henrik Grubbström (Grubba)  Pike_sp+3-args, "End 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);
a52ec22017-02-15Henrik Grubbström (Grubba)  if (start >= end) { start = -1; }
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:
f54c782004-12-22Henrik Grubbström (Grubba)  { struct program *p; if ((p = (Pike_sp[-args].u.object->prog))) { struct object *o = Pike_sp[-args].u.object;
017b572011-10-28Henrik Grubbström (Grubba)  int id_level = p->inherits[SUBTYPEOF(Pike_sp[-args])].identifier_level;
f54c782004-12-22Henrik Grubbström (Grubba)  int id; int next, ind;
017b572011-10-28Henrik Grubbström (Grubba)  p = p->inherits[SUBTYPEOF(Pike_sp[-args])].prog;
f54c782004-12-22Henrik Grubbström (Grubba)  /* NOTE: Fake lfun! */ id = low_find_lfun(p, LFUN__SEARCH); /* First try lfun::_search(). */ if (id >= 0) { apply_low(o, id + id_level, args-1); stack_pop_n_elems_keep_top(1); return;
b5b59a2003-09-04Henrik Grubbström (Grubba)  }
f54c782004-12-22Henrik Grubbström (Grubba)  /* Check if we have an iterator. */ if (((id = find_identifier("value", p)) >= 0) && ((next = find_identifier("next", p)) >= 0) && ((ind = find_identifier("index", p)) >= 0)) { /* We have an iterator. */ id += id_level; next += id_level; ind += id_level; /* Set the start position if needed. */ if (args > 2) { int fun = find_identifier("set_index", p); if (fun < 0) Pike_error ("Cannot call unknown function \"%s\".\n", fun); apply_low(o, fun + id_level, args-2); pop_stack();
b5b59a2003-09-04Henrik Grubbström (Grubba)  }
f54c782004-12-22Henrik Grubbström (Grubba)  /* At this point we have two values on the stack. */ while(1) { apply_low(o, id, 0); if (is_eq(Pike_sp-2, Pike_sp-1)) { /* Found. */ apply_low(o, ind, 0); stack_pop_n_elems_keep_top(3); return; } apply_low(o, next, 0); 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. */
13670c2015-05-25Martin Nilsson  push_undefined();
f54c782004-12-22Henrik Grubbström (Grubba)  return; } pop_n_elems(2);
b5b59a2003-09-04Henrik Grubbström (Grubba)  } } } }
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
5267b71995-08-09Fredrik Hübinette (Hubbe)  default:
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("search", 1, "string|array|mapping|object");
5267b71995-08-09Fredrik Hübinette (Hubbe)  } }
929a862010-02-23Henrik Grubbström (Grubba) /*! @decl int has_prefix(string|object s, string prefix)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
cbe8c92003-04-07Martin Nilsson  *! Returns @expr{1@} if the string @[s] starts with @[prefix], *! returns @expr{0@} (zero) otherwise.
38cb402010-03-30Peter Bortas  *!
dfaa432010-11-15Henrik Grubbström (Grubba)  *! When @[s] is an object, it needs to implement *! @[lfun::_sizeof()] and @[lfun::`[]]. *!
38cb402010-03-30Peter Bortas  *! @seealso *! @[has_suffix()], @[has_value()], @[search()]
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;
06bd612016-01-26Martin Nilsson  if(args!=2) SIMPLE_WRONG_NUM_ARGS_ERROR("has_prefix", 2);
017b572011-10-28Henrik Grubbström (Grubba)  if((TYPEOF(Pike_sp[-args]) != T_STRING) && (TYPEOF(Pike_sp[-args]) != T_OBJECT))
929a862010-02-23Henrik Grubbström (Grubba)  SIMPLE_ARG_TYPE_ERROR("has_prefix", 1, "string|object");
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[1-args]) != T_STRING)
7d1e032004-05-18Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("has_prefix", 2, "string"); b = Pike_sp[1-args].u.string;
a4f17f2000-04-12Henrik Grubbström (Grubba) 
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-args]) == T_OBJECT) {
929a862010-02-23Henrik Grubbström (Grubba)  ptrdiff_t i; struct object *o = Pike_sp[-args].u.object;
017b572011-10-28Henrik Grubbström (Grubba)  int inherit_no = SUBTYPEOF(Pike_sp[-args]);
dfaa432010-11-15Henrik Grubbström (Grubba) 
e305422012-05-11Henrik Grubbström (Grubba)  if (!o->prog || FIND_LFUN(o->prog, LFUN__SIZEOF) < 0) {
3686232014-08-18Martin Nilsson  Pike_error("Object in argument 1 lacks lfun::_sizeof().\n");
e305422012-05-11Henrik Grubbström (Grubba)  }
dfaa432010-11-15Henrik Grubbström (Grubba)  apply_lfun(o, LFUN__SIZEOF, 0);
017b572011-10-28Henrik Grubbström (Grubba)  if ((TYPEOF(Pike_sp[-1]) != T_INT) || (Pike_sp[-1].u.integer < b->len)) {
dfaa432010-11-15Henrik Grubbström (Grubba)  pop_n_elems(args + 1); push_int(0); return; }
929a862010-02-23Henrik Grubbström (Grubba)  for (i = 0; i < b->len; i++) { p_wchar2 ch = index_shared_string(b, i); Pike_sp[-1].u.integer = i; /* Note: Integers do not need to be freed. */ object_index_no_free(Pike_sp-1, o, inherit_no, Pike_sp-1);
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-1]) != PIKE_T_INT) {
929a862010-02-23Henrik Grubbström (Grubba)  Pike_error("Unexepected value returned from index operator.\n"); } if (ch != Pike_sp[-1].u.integer) { pop_n_elems(args + 1); push_int(0); return; } }
36f1052010-02-23Henrik Grubbström (Grubba)  pop_n_elems(args+1);
929a862010-02-23Henrik Grubbström (Grubba)  push_int(1); return; } a = Pike_sp[-args].u.string;
a4f17f2000-04-12Henrik Grubbström (Grubba)  /* First handle some common special cases. */
6765822013-06-10Tobias S. Josefowitz  if ((b->len > a->len) || (b->size_shift > a->size_shift) || !string_range_contains_string(a, b)) {
a4f17f2000-04-12Henrik Grubbström (Grubba)  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) {
67074e2014-09-03Martin Nilsson  int res = !memcmp(a->str, b->str, b->len << b->size_shift);
a4f17f2000-04-12Henrik Grubbström (Grubba)  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); } #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.
38cb402010-03-30Peter Bortas  *! *! @seealso *! @[has_prefix()], @[has_value()], @[search()]
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;
06bd612016-01-26Martin Nilsson  if(args!=2) SIMPLE_WRONG_NUM_ARGS_ERROR("has_suffix", 2);
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[-args]) != T_STRING)
7d1e032004-05-18Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("has_suffix", 1, "string");
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[1-args]) != T_STRING)
7d1e032004-05-18Martin Nilsson  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. */
6765822013-06-10Tobias S. Josefowitz  if ((b->len > a->len) || (b->size_shift > a->size_shift) || !string_range_contains_string(a, b)) {
54277b2000-12-18Henrik Grubbström (Grubba)  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) {
67074e2014-09-03Martin Nilsson  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); } #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
38cb402010-03-30Peter Bortas  *! @[has_value()], @[has_prefix()], @[has_suffix()], @[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;
13670c2015-05-25Martin Nilsson 
06bd612016-01-26Martin Nilsson  if(args != 2) SIMPLE_WRONG_NUM_ARGS_ERROR("has_index", 2);
538a892000-01-21Fredrik Noring 
017b572011-10-28Henrik Grubbström (Grubba)  switch(TYPEOF(Pike_sp[-2]))
538a892000-01-21Fredrik Noring  { case T_STRING:
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[-1]) == T_INT)
edf4d02000-07-06Fredrik Hübinette (Hubbe)  t = (0 <= Pike_sp[-1].u.integer && Pike_sp[-1].u.integer < Pike_sp[-2].u.string->len);
13670c2015-05-25Martin Nilsson 
538a892000-01-21Fredrik Noring  pop_n_elems(args); push_int(t); break;
13670c2015-05-25Martin Nilsson 
538a892000-01-21Fredrik Noring  case T_ARRAY:
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[-1]) == T_INT)
edf4d02000-07-06Fredrik Hübinette (Hubbe)  t = (0 <= Pike_sp[-1].u.integer && Pike_sp[-1].u.integer < Pike_sp[-2].u.array->size);
13670c2015-05-25Martin Nilsson 
538a892000-01-21Fredrik Noring  pop_n_elems(args); push_int(t); break;
13670c2015-05-25Martin Nilsson 
538a892000-01-21Fredrik Noring  case T_MAPPING:
b3f9b22015-03-31Per Hedbor  t=!!low_mapping_lookup( Pike_sp[-2].u.mapping, Pike_sp-1 ); pop_n_elems(2); push_int(t); break; case T_MULTISET: t = multiset_member( Pike_sp[-2].u.multiset, Pike_sp-1 ); pop_n_elems(2); push_int(t); break;
13670c2015-05-25Martin Nilsson 
538a892000-01-21Fredrik Noring  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.
13670c2015-05-25Martin Nilsson 
538a892000-01-21Fredrik Noring  /Noring */
89c91b2008-01-05Martin Nilsson  /* If it is an iterator object we may want to use the iterator interface to look for the index. */
538a892000-01-21Fredrik Noring  stack_swap(); f_indices(1); stack_swap(); f_search(2);
13670c2015-05-25Martin Nilsson 
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[-1]) == T_INT)
edf4d02000-07-06Fredrik Hübinette (Hubbe)  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
13670c2015-05-25Martin Nilsson  *! @[has_index()], @[indices()], @[search()], @[has_prefix()],
38cb402010-03-30Peter Bortas  *! @[has_suffix()], @[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 {
06bd612016-01-26Martin Nilsson  if(args != 2) SIMPLE_WRONG_NUM_ARGS_ERROR("has_value", 2);
538a892000-01-21Fredrik Noring 
017b572011-10-28Henrik Grubbström (Grubba)  switch(TYPEOF(Pike_sp[-2]))
538a892000-01-21Fredrik Noring  { case T_MAPPING: f_search(2); f_zero_type(1);
13670c2015-05-25Martin Nilsson 
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[-1]) == T_INT)
edf4d02000-07-06Fredrik Hübinette (Hubbe)  Pike_sp[-1].u.integer = !Pike_sp[-1].u.integer;
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
f54c782004-12-22Henrik Grubbström (Grubba)  use `search' directly since it's undefined whether it returns
538a892000-01-21Fredrik Noring  -1 (array) or 0 (mapping) during e.g. some data type emulation.
13670c2015-05-25Martin Nilsson 
7b58042000-01-24Fredrik Noring  Maybe we should use object->_has_value(value) provided that the object implements it.
13670c2015-05-25Martin Nilsson 
538a892000-01-21Fredrik Noring  /Noring */
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
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();
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
01587a2003-06-03Martin Stjernholm 
aa14882000-01-24Martin Stjernholm  case T_STRING: /* Strings are odd. /Noring */
538a892000-01-21Fredrik Noring  case T_ARRAY: f_search(2);
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[-1]) == T_INT)
edf4d02000-07-06Fredrik Hübinette (Hubbe)  Pike_sp[-1].u.integer = (Pike_sp[-1].u.integer != -1);
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) { if(args<1)
06bd612016-01-26Martin Nilsson  SIMPLE_WRONG_NUM_ARGS_ERROR("add_constant", 1);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[-args]) != T_STRING)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_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)
0c95942018-01-12Stephen R. van den Berg  *! @decl string combine_path_amigaos(string path, string ... paths)
f7fb1a2004-05-01Martin Stjernholm  *! *! 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
0c95942018-01-12Stephen R. van den Berg  *! front of absolute paths). @[combine_path_amigaos()] concatenates *! according to AmigaOS filesystem conventions.
97e8162004-05-01Martin Stjernholm  *! *! @[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
0c95942018-01-12Stephen R. van den Berg  *! 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) 
0c95942018-01-12Stephen R. van den Berg #define AMIGAOS_COMBINE_PATH #include "combine_path.h"
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) {
06bd612016-01-26Martin Nilsson  if(args != 1) SIMPLE_WRONG_NUM_ARGS_ERROR("zero_type",1);
8aefbc1999-03-19Fredrik Hübinette (Hubbe) 
38b42c2015-05-21Tobias S. Josefowitz  if(IS_DESTRUCTED(Pike_sp-args))
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)  }
017b572011-10-28Henrik Grubbström (Grubba)  else if(TYPEOF(Pike_sp[-args]) != 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);
017b572011-10-28Henrik Grubbström (Grubba)  Pike_sp[-1].u.integer = SUBTYPEOF(Pike_sp[-1]); SET_SVAL_SUBTYPE(Pike_sp[-1], NUMBER_NUMBER);
3f6d8f1996-11-26Fredrik Hübinette (Hubbe)  }
5267b71995-08-09Fredrik Hübinette (Hubbe) }
263ea32014-08-18Per Hedbor static int generate_arg_for(node *n)
0811472001-07-02Fredrik Hübinette (Hubbe) { 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");
263ea32014-08-18Per Hedbor  return 1; } static int generate_zero_type(node *n) { struct compilation *c = THIS_COMPILATION; if( generate_arg_for( n ) ) emit0(F_ZERO_TYPE); else return 0; return 1; } static int generate_undefinedp(node *n) { struct compilation *c = THIS_COMPILATION; if( generate_arg_for(n) ) emit0(F_UNDEFINEDP); else return 0; return 1; } static int generate_destructedp(node *n) { struct compilation *c = THIS_COMPILATION; if( generate_arg_for(n) ) emit0(F_DESTRUCTEDP); else return 0;
0811472001-07-02Fredrik Hübinette (Hubbe)  return 1; }
4643ea1998-10-10Henrik Grubbström (Grubba) /* * Some wide-strings related functions */
053b2d2015-06-05Henrik Grubbström (Grubba) /*! @decl string(0..255) string_to_unicode(string s, int(0..2)|void byteorder)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Converts a string into an UTF16 compliant byte-stream.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
053b2d2015-06-05Henrik Grubbström (Grubba)  *! @param s *! String to convert to UTF16. *! *! @param byteorder *! Byte-order for the output. One of: *! @int *! @value 0 *! Network (aka big-endian) byte-order (default). *! @value 1 *! Little-endian byte-order. *! @value 2 *! Native byte-order. *! @endint *!
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
0b8d2f2013-06-17Martin Nilsson  *! @[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;
053b2d2015-06-05Henrik Grubbström (Grubba)  unsigned INT_TYPE byteorder = 0;
4643ea1998-10-10Henrik Grubbström (Grubba) 
053b2d2015-06-05Henrik Grubbström (Grubba)  get_all_args("string_to_unicode", args, "%W.%i", &in, &byteorder); if (byteorder >= 2) { if (byteorder == 2) { #if PIKE_BYTEORDER == 1234 /* Little endian. */ byteorder = 1; #else byteorder = 0; #endif } else {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("string_to_unicode", 2, "int(0..2)|void");
053b2d2015-06-05Henrik Grubbström (Grubba)  } }
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) {
21b12a2014-09-03Martin Nilsson  memset(out->str, 0, len); /* Clear the upper (and lower) byte */
89a70c2000-08-28Henrik Grubbström (Grubba)  for(i = in->len; i--;) {
053b2d2015-06-05Henrik Grubbström (Grubba)  out->str[i * 2 + 1 - byteorder] = in->str[i];
89a70c2000-08-28Henrik Grubbström (Grubba)  }
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);
053b2d2015-06-05Henrik Grubbström (Grubba)  if (byteorder ==
71f3a21998-11-22Fredrik Hübinette (Hubbe) #if (PIKE_BYTEORDER == 4321)
053b2d2015-06-05Henrik Grubbström (Grubba)  1 /* Little endian. */
4643ea1998-10-10Henrik Grubbström (Grubba) #else
053b2d2015-06-05Henrik Grubbström (Grubba)  0 /* Big endian. */ #endif ) { /* Other endianness, may need to do byte-order conversion also. */
4643ea1998-10-10Henrik Grubbström (Grubba)  p_wchar1 *str1 = STR1(in); for(i = in->len; i--;) { unsigned INT32 c = str1[i];
053b2d2015-06-05Henrik Grubbström (Grubba)  out->str[i * 2 + 1 - byteorder] = c & 0xff; out->str[i * 2 + byteorder] = c >> 8;
4643ea1998-10-10Henrik Grubbström (Grubba)  }
053b2d2015-06-05Henrik Grubbström (Grubba)  } else { /* Native byte order -- 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);
4643ea1998-10-10Henrik Grubbström (Grubba)  } 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. */
3686232014-08-18Martin Nilsson  Pike_error("Illegal character 0x%04x (index %ld) " "is not a Unicode character.",
6da27e2016-02-12Martin Nilsson  str2[i], (long)i);
4643ea1998-10-10Henrik Grubbström (Grubba)  } if (str2[i] > 0x10ffff) {
3686232014-08-18Martin Nilsson  Pike_error("Character 0x%08x (index %ld) " "is out of range (0x00000000..0x0010ffff).",
6da27e2016-02-12Martin Nilsson  str2[i], (long)i);
4643ea1998-10-10Henrik Grubbström (Grubba)  }
053b2d2015-06-05Henrik Grubbström (Grubba)  /* Extra wide characters take two UTF16 characters in space. * ie One UTF16 character extra.
4643ea1998-10-10Henrik Grubbström (Grubba)  */ 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;
13670c2015-05-25Martin Nilsson 
053b2d2015-06-05Henrik Grubbström (Grubba)  out->str[j + 1 - byteorder] = c & 0xff; out->str[j + byteorder] = 0xdc | ((c >> 8) & 0x03);
4643ea1998-10-10Henrik Grubbström (Grubba)  j -= 2; c >>= 10; c |= 0xd800; }
053b2d2015-06-05Henrik Grubbström (Grubba)  out->str[j + 1 - byteorder] = c & 0xff; out->str[j + byteorder] = c >> 8;
4643ea1998-10-10Henrik Grubbström (Grubba)  }
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",
6da27e2016-02-12Martin Nilsson  (long)len, (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; } pop_n_elems(args); push_string(out); }
c5046a2015-06-05Henrik Grubbström (Grubba) /*! @decl string unicode_to_string(string(0..255) s, int(0..2)|void byteorder)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Converts an UTF16 byte-stream into a string.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
c5046a2015-06-05Henrik Grubbström (Grubba)  *! @param s *! String to convert to UTF16. *! *! @param byteorder *! Default input byte-order. One of: *! @int *! @value 0 *! Network (aka big-endian) byte-order (default). *! @value 1 *! Little-endian byte-order. *! @value 2 *! Native byte-order. *! @endint *! Note that this argument is disregarded if @[s] starts with a BOM. *!
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! @seealso
0b8d2f2013-06-17Martin Nilsson  *! @[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;
c5046a2015-06-05Henrik Grubbström (Grubba)  INT_TYPE byteorder = 0;
f272792001-04-18Marcus Comstedt  int swab=0; p_wchar1 surr1, surr2, surrmask, *str0;
4643ea1998-10-10Henrik Grubbström (Grubba) 
c5046a2015-06-05Henrik Grubbström (Grubba)  get_all_args("unicode_to_string", args, "%S.%i", &in, &byteorder);
4643ea1998-10-10Henrik Grubbström (Grubba)  if (in->len & 1) {
212c392018-02-25Martin Nilsson  bad_arg_error("unicode_to_string", args, 1, "string", Pike_sp-args,
d0d01b1999-03-20Henrik Grubbström (Grubba)  "String length is odd.\n");
4643ea1998-10-10Henrik Grubbström (Grubba)  }
c5046a2015-06-05Henrik Grubbström (Grubba)  if (byteorder >= 2) { if (byteorder == 2) { #if PIKE_BYTEORDER == 1234 /* Little endian. */ byteorder = 1; #else byteorder = 0; #endif } else {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("unicode_to_string", 2, "int(0..2)|void");
c5046a2015-06-05Henrik Grubbström (Grubba)  } } if (byteorder != #if PIKE_BYTEORDER == 1234 1 #else 0 #endif ) { /* Need to swap as the wanted byte-order differs * from the native byte-order. */ swab = 1; }
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 {
c5046a2015-06-05Henrik Grubbström (Grubba)  /* No byte order mark. Use the user-specified byte-order. */
f272792001-04-18Marcus Comstedt  } /* 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) {
13670c2015-05-25Martin Nilsson 
f272792001-04-18Marcus Comstedt  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. */
c9d3972014-09-03Martin Nilsson  memcpy(out->str, str0-len, len*2);
f272792001-04-18Marcus Comstedt  } else { /* Reverse endian */
13670c2015-05-25Martin Nilsson 
f272792001-04-18Marcus Comstedt  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) {
13670c2015-05-25Martin Nilsson 
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); }
9765732014-05-22Per Hedbor /*! @decl string(1..) string_filter_non_unicode(string s) *! *! Replace the most obviously non-unicode characters from @[s] with *! the unicode replacement character. *! *! @note *! This will replace characters outside the ranges *! @expr{0x00000000-0x0000d7ff@} and @expr{0x0000e000-0x0010ffff@} *! with 0xffea (the replacement character). *! *! @seealso *! @[Charset.encoder()], @[string_to_unicode()], *! @[unicode_to_string()], @[utf8_to_string()], @[string_to_utf8()] */ static void f_string_filter_non_unicode( INT32 args ) { struct pike_string *in; INT32 min,max; int i; static const p_wchar1 replace = 0xfffd; static const PCHARP repl_char = {(void*)&replace,1}; get_all_args("filter_non_unicode", args, "%W", &in); check_string_range( in, 1, &min, &max ); if( !in->len || (min >= 0 && max < 0xd800) ) return; /* The string is obviously ok. */ if( (max < 0 || min > 0x10ffff) || (max < 0xe000 && min > 0xd7ff) ) { /* All invalid. Could probably be optimized. */ debug_make_shared_binary_pcharp( repl_char, 1 ); push_int( in->len ); o_multiply(); } else { /* Note: we could optimize this by not doing any string builder * at all unless there is at least one character that needs to * be replaced. */ struct string_builder out; /* on average shift 1 is more correct than in->size_shift, since * there is usually only the one character that is outside the * range. */ init_string_builder_alloc( &out, in->len, 1 ); for( i=0; i<in->len; i++ ) { p_wchar2 c = index_shared_string(in,i); if( (c < 0 || c > 0x10ffff) || (c>0xd7ff && c<0xe000) ) string_builder_append( &out, repl_char, 1 ); else string_builder_putchar( &out, c ); } push_string( finish_string_builder( &out ) ); } }
81ac8e2018-04-22Henrik Grubbström (Grubba) /*! @decl utf8_string string_to_utf8(string s) *! @decl utf8_string string_to_utf8(string s, int extended)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
f16cbc2018-05-24Henrik Grubbström (Grubba)  *! Convert a string into a UTF-8 compliant byte-stream. *! *! @param s *! String to encode into UTF-8. *! *! @param extended *! Bitmask with extension options. *! @int *! @value 1 *! Accept and encode the characters outside the valid ranges *! using the same algorithm. Such encoded characters are *! however not UTF-8 compliant. *! @value 2 *! Encode characters outside the BMP with UTF-8 encoded UTF-16 *! (ie split them into surrogate pairs and encode). *! @endint
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @note
dee8942005-04-02Martin Stjernholm  *! Throws an error if characters not valid in an UTF-8 stream are *! encountered. Valid characters are in the ranges *! @expr{0x00000000-0x0000d7ff@} and @expr{0x0000e000-0x0010ffff@}.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
0b8d2f2013-06-17Martin Nilsson  *! @[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;
e4808d2016-10-28Arne Goedeke  ptrdiff_t i;
2adf002004-02-29Martin Stjernholm  INT_TYPE extended = 0;
52b5d92013-05-17Arne Goedeke  PCHARP src;
1ac9ce2013-06-10Arne Goedeke  INT32 min, max;
e4808d2016-10-28Arne Goedeke  unsigned char * dst;
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;
1ac9ce2013-06-10Arne Goedeke  check_string_range(in, 1, &min, &max); if (min >= 0 && max <= 0x7f) { /* 7bit string -- already valid utf8. */ pop_n_elems(args - 1); return; }
52b5d92013-05-17Arne Goedeke  for(i=0,src=MKPCHARP_STR(in); i < in->len; INC_PCHARP(src,1),i++) { unsigned INT32 c = EXTRACT_PCHARP(src);
be40771998-10-15Henrik Grubbström (Grubba)  if (c & ~0x7f) { /* 8bit or more. */ len++; if (c & ~0x7ff) { /* 12bit or more. */ len++; if (c & ~0xffff) { /* 17bit or more. */ len++;
f16cbc2018-05-24Henrik Grubbström (Grubba)  if (!(extended & 1) && c > 0x10ffff)
212c392018-02-25Martin Nilsson  bad_arg_error ("string_to_utf8", args, 1,
dee8942005-04-02Martin Stjernholm  NULL, Pike_sp - args, "Character 0x%08x at index %"PRINTPTRDIFFT"d is " "outside the allowed range.\n", c, i);
f16cbc2018-05-24Henrik Grubbström (Grubba)  if ((extended & 2) && (c <= 0x10ffff)) { /* Encode with a surrogate pair. */ len += 2; } else if (c & ~0x1fffff) {
be40771998-10-15Henrik Grubbström (Grubba)  /* 22bit or more. */ len++; if (c & ~0x3ffffff) { /* 27bit or more. */ len++; if (c & ~0x7fffffff) { /* 32bit or more. */ len++; /* FIXME: Needs fixing when we get 64bit chars... */ } } } }
f16cbc2018-05-24Henrik Grubbström (Grubba)  else if (!(extended & 1) && c >= 0xd800 && c <= 0xdfff)
212c392018-02-25Martin Nilsson  bad_arg_error ("string_to_utf8", args, 1,
dee8942005-04-02Martin Stjernholm  NULL, Pike_sp - args, "Character 0x%08x at index %"PRINTPTRDIFFT"d is " "in the surrogate range and therefore invalid.\n", c, i);
be40771998-10-15Henrik Grubbström (Grubba)  } } } 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);
e4808d2016-10-28Arne Goedeke  dst = STR0(out);
be40771998-10-15Henrik Grubbström (Grubba) 
e4808d2016-10-28Arne Goedeke  for(i=0,src=MKPCHARP_STR(in); i < in->len; INC_PCHARP(src,1),i++) {
52b5d92013-05-17Arne Goedeke  unsigned INT32 c = EXTRACT_PCHARP(src);
be40771998-10-15Henrik Grubbström (Grubba)  if (!(c & ~0x7f)) { /* 7bit */
e4808d2016-10-28Arne Goedeke  *dst++ = c;
be40771998-10-15Henrik Grubbström (Grubba)  } else if (!(c & ~0x7ff)) { /* 11bit */
e4808d2016-10-28Arne Goedeke  *dst++ = 0xc0 | (c >> 6); *dst++ = 0x80 | (c & 0x3f);
be40771998-10-15Henrik Grubbström (Grubba)  } else if (!(c & ~0xffff)) { /* 16bit */
e4808d2016-10-28Arne Goedeke  *dst++ = 0xe0 | (c >> 12); *dst++ = 0x80 | ((c >> 6) & 0x3f); *dst++ = 0x80 | (c & 0x3f);
f16cbc2018-05-24Henrik Grubbström (Grubba)  } else if ((extended & 2) && (c <= 0x10ffff)) { /* Encode with surrogates. */ c -= 0x10000; /* 0xd800 | (c>>10) * 0b1101 10cccc cccccc * UTF8: 11101101 1010cccc 10cccccc */
9abe6a2018-05-24Henrik Grubbström (Grubba)  *dst++ = 0xed; *dst++ = 0xa0 | (c >> 16); *dst++ = 0x80 | ((c >> 10) & 0x3f);
f16cbc2018-05-24Henrik Grubbström (Grubba)  /* 0xdc00 | (c & 0x3ff) * 0b1101 11cccc cccccc * UTF8: 11101101 1011cccc 10cccccc */
9abe6a2018-05-24Henrik Grubbström (Grubba)  *dst++ = 0xed; *dst++ = 0xb0 | ((c >> 6) & 0x3f); *dst++ = 0x80 | (c & 0x3f);
be40771998-10-15Henrik Grubbström (Grubba)  } else if (!(c & ~0x1fffff)) { /* 21bit */
e4808d2016-10-28Arne Goedeke  *dst++ = 0xf0 | (c >> 18); *dst++ = 0x80 | ((c >> 12) & 0x3f); *dst++ = 0x80 | ((c >> 6) & 0x3f); *dst++ = 0x80 | (c & 0x3f);
be40771998-10-15Henrik Grubbström (Grubba)  } else if (!(c & ~0x3ffffff)) { /* 26bit */
e4808d2016-10-28Arne Goedeke  *dst++ = 0xf8 | (c >> 24); *dst++ = 0x80 | ((c >> 18) & 0x3f); *dst++ = 0x80 | ((c >> 12) & 0x3f); *dst++ = 0x80 | ((c >> 6) & 0x3f); *dst++ = 0x80 | (c & 0x3f);
be40771998-10-15Henrik Grubbström (Grubba)  } else if (!(c & ~0x7fffffff)) { /* 31bit */
e4808d2016-10-28Arne Goedeke  *dst++ = 0xfc | (c >> 30); *dst++ = 0x80 | ((c >> 24) & 0x3f); *dst++ = 0x80 | ((c >> 18) & 0x3f); *dst++ = 0x80 | ((c >> 12) & 0x3f); *dst++ = 0x80 | ((c >> 6) & 0x3f); *dst++ = 0x80 | (c & 0x3f);
be40771998-10-15Henrik Grubbström (Grubba)  } else { /* 32 - 36bit */
e4808d2016-10-28Arne Goedeke  *dst++ = (char)0xfe; *dst++ = 0x80 | ((c >> 30) & 0x3f); *dst++ = 0x80 | ((c >> 24) & 0x3f); *dst++ = 0x80 | ((c >> 18) & 0x3f); *dst++ = 0x80 | ((c >> 12) & 0x3f); *dst++ = 0x80 | ((c >> 6) & 0x3f); *dst++ = 0x80 | (c & 0x3f);
be40771998-10-15Henrik Grubbström (Grubba)  } }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
e4808d2016-10-28Arne Goedeke  if (len != dst - STR0(out)) {
5aad932002-08-15Marcus Comstedt  Pike_fatal("string_to_utf8(): Calculated and actual lengths differ: "
e4808d2016-10-28Arne Goedeke  "%"PRINTPTRDIFFT"d != %"PRINTPTRDIFFT"d\n", len, dst - STR0(out));
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); }
81ac8e2018-04-22Henrik Grubbström (Grubba) /*! @decl string utf8_to_string(utf8_string s) *! @decl string utf8_to_string(utf8_string s, int extended)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
dee8942005-04-02Martin Stjernholm  *! Converts an UTF-8 byte-stream into a string.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
6aebbf2012-02-23Henrik Grubbström (Grubba)  *! @param s *! String of UTF-8 encoded data to decode. *! *! @param extended *! Bitmask with extension options. *! @int *! @value 1 *! Accept and decode the extension used by @[string_to_utf8()]. *! @value 2 *! Accept and decode UTF-8 encoded UTF-16 (ie accept and *! decode valid surrogates). *! @endint *!
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! @note
dee8942005-04-02Martin Stjernholm  *! Throws an error if the stream is not a legal UTF-8 byte-stream.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
dee8942005-04-02Martin Stjernholm  *! @note
974d4a2015-08-22Martin Nilsson  *! In conformance with @rfc{3629@} and Unicode 3.1 and later,
7931822005-08-01Martin Stjernholm  *! non-shortest forms are not decoded. An error is thrown instead.
dee8942005-04-02Martin Stjernholm  *!
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! @seealso
0b8d2f2013-06-17Martin Nilsson  *! @[Charset.encoder()], @[string_to_unicode()], @[string_to_utf8()],
5845a72018-05-17Henrik Grubbström (Grubba)  *! @[unicode_to_string()], @[validate_utf8()]
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;
dee8942005-04-02Martin Stjernholm  ptrdiff_t len = 0;
be40771998-10-15Henrik Grubbström (Grubba)  int shift = 0;
cc724f2005-05-05Martin Nilsson  ptrdiff_t i,j=0;
2adf002004-02-29Martin Stjernholm  INT_TYPE extended = 0;
1ac9ce2013-06-10Arne Goedeke  INT32 min, max;
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) 
1ac9ce2013-06-10Arne Goedeke  check_string_range(in, 1, &min, &max); if (min >= 0 && max <= 0x7f) { /* 7bit string -- already valid utf8. */ pop_n_elems(args - 1); return; }
be40771998-10-15Henrik Grubbström (Grubba)  for(i=0; i < in->len; i++) {
57dd672005-04-02Martin Stjernholm  unsigned int c = STR0(in)[i];
be40771998-10-15Henrik Grubbström (Grubba)  len++; if (c & 0x80) { int cont = 0;
dee8942005-04-02Martin Stjernholm  /* From table 3-6 in the Unicode standard 4.0: Well-Formed UTF-8 * Byte Sequences * * Code Points 1st Byte 2nd Byte 3rd Byte 4th Byte * 000000-00007f 00-7f * 000080-0007ff c2-df 80-bf * 000800-000fff e0 a0-bf 80-bf * 001000-00cfff e1-ec 80-bf 80-bf * 00d000-00d7ff ed 80-9f 80-bf * 00e000-00ffff ee-ef 80-bf 80-bf * 010000-03ffff f0 90-bf 80-bf 80-bf * 040000-0fffff f1-f3 80-bf 80-bf 80-bf * 100000-10ffff f4 80-8f 80-bf 80-bf */
be40771998-10-15Henrik Grubbström (Grubba)  if ((c & 0xc0) == 0x80) {
212c392018-02-25Martin Nilsson  bad_arg_error ("utf8_to_string", args, 1,
dee8942005-04-02Martin Stjernholm  NULL, Pike_sp - args, "Invalid continuation character 0x%02x " "at index %"PRINTPTRDIFFT"d.\n", c, i);
be40771998-10-15Henrik Grubbström (Grubba)  }
dee8942005-04-02Martin Stjernholm 
6aebbf2012-02-23Henrik Grubbström (Grubba) #define GET_CHAR(in, i, c) do { \
dee8942005-04-02Martin Stjernholm  i++; \ if (i >= in->len) \
212c392018-02-25Martin Nilsson  bad_arg_error ("utf8_to_string", args, 1, \
dee8942005-04-02Martin Stjernholm  NULL, Pike_sp - args, \ "Truncated UTF-8 sequence at end of string.\n"); \
57dd672005-04-02Martin Stjernholm  c = STR0 (in)[i]; \
6aebbf2012-02-23Henrik Grubbström (Grubba)  } while(0) #define GET_CONT_CHAR(in, i, c) do { \ GET_CHAR(in, i, c); \
dee8942005-04-02Martin Stjernholm  if ((c & 0xc0) != 0x80) \
212c392018-02-25Martin Nilsson  bad_arg_error ("utf8_to_string", args, 1, \
dee8942005-04-02Martin Stjernholm  NULL, Pike_sp - args, \ "Expected continuation character at index %d, " \ "got 0x%02x.\n", \ i, c); \ } while (0) #define UTF8_SEQ_ERROR(prefix, c, i, problem) do { \
212c392018-02-25Martin Nilsson  bad_arg_error ("utf8_to_string", args, 1, \
dee8942005-04-02Martin Stjernholm  NULL, Pike_sp - args, \ "UTF-8 sequence beginning with %s0x%02x " \ "at index %"PRINTPTRDIFFT"d %s.\n", \ prefix, c, i, problem); \ } while (0)
be40771998-10-15Henrik Grubbström (Grubba)  if ((c & 0xe0) == 0xc0) { /* 11bit */
dee8942005-04-02Martin Stjernholm  if (!(c & 0x1e)) UTF8_SEQ_ERROR ("", c, i, "is a non-shortest form");
be40771998-10-15Henrik Grubbström (Grubba)  cont = 1; if (c & 0x1c) { if (shift < 1) { shift = 1; } }
dee8942005-04-02Martin Stjernholm  } else if ((c & 0xf0) == 0xe0) {
be40771998-10-15Henrik Grubbström (Grubba)  /* 16bit */
dee8942005-04-02Martin Stjernholm  if (c == 0xe0) { GET_CONT_CHAR (in, i, c); if (!(c & 0x20)) UTF8_SEQ_ERROR ("0xe0 ", c, i - 1, "is a non-shortest form"); cont = 1; }
6aebbf2012-02-23Henrik Grubbström (Grubba)  else if (!(extended & 1) && c == 0xed) {
dee8942005-04-02Martin Stjernholm  GET_CONT_CHAR (in, i, c);
6aebbf2012-02-23Henrik Grubbström (Grubba)  if (c & 0x20) { /* Surrogate. */ if (!(extended & 2)) { UTF8_SEQ_ERROR ("0xed ", c, i - 1, "would decode to " "a UTF-16 surrogate character"); } if (c & 0x10) { UTF8_SEQ_ERROR ("0xed ", c, i - 1, "would decode to " "a UTF-16 low surrogate character"); } GET_CONT_CHAR(in, i, c); GET_CHAR (in, i, c); if (c != 0xed) { UTF8_SEQ_ERROR ("", c, i-1, "UTF-16 low surrogate " "character required"); } GET_CONT_CHAR (in, i, c); if ((c & 0xf0) != 0xb0) { UTF8_SEQ_ERROR ("0xed ", c, i-1, "UTF-16 low surrogate " "character required"); } shift = 2; }
dee8942005-04-02Martin Stjernholm  cont = 1; } else cont = 2;
be40771998-10-15Henrik Grubbström (Grubba)  if (shift < 1) { shift = 1; }
dee8942005-04-02Martin Stjernholm  } else {
be40771998-10-15Henrik Grubbström (Grubba)  if ((c & 0xf8) == 0xf0) { /* 21bit */
dee8942005-04-02Martin Stjernholm  if (c == 0xf0) { GET_CONT_CHAR (in, i, c); if (!(c & 0x30)) UTF8_SEQ_ERROR ("0xf0 ", c, i - 1, "is a non-shortest form"); cont = 2;
ed65901998-10-31Henrik Grubbström (Grubba)  }
6aebbf2012-02-23Henrik Grubbström (Grubba)  else if (!(extended & 1)) {
dee8942005-04-02Martin Stjernholm  if (c > 0xf4) UTF8_SEQ_ERROR ("", c, i, "would decode to " "a character outside the valid UTF-8 range"); else if (c == 0xf4) { GET_CONT_CHAR (in, i, c); if (c > 0x8f) UTF8_SEQ_ERROR ("0xf4 ", c, i - 1, "would decode to " "a character outside the valid UTF-8 range"); cont = 2; } else cont = 3; } else cont = 3;
be40771998-10-15Henrik Grubbström (Grubba)  }
dee8942005-04-02Martin Stjernholm  else if (c == 0xff)
212c392018-02-25Martin Nilsson  bad_arg_error ("utf8_to_string", args, 1,
dee8942005-04-02Martin Stjernholm  NULL, Pike_sp - args, "Invalid character 0xff at index %"PRINTPTRDIFFT"d.\n", i);
6aebbf2012-02-23Henrik Grubbström (Grubba)  else if (!(extended & 1))
dee8942005-04-02Martin Stjernholm  UTF8_SEQ_ERROR ("", c, i, "would decode to " "a character outside the valid UTF-8 range"); else { if ((c & 0xfc) == 0xf8) { /* 26bit */ if (c == 0xf8) { GET_CONT_CHAR (in, i, c); if (!(c & 0x38)) UTF8_SEQ_ERROR ("0xf8 ", c, i - 1, "is a non-shortest form"); cont = 3; } else cont = 4; } else if ((c & 0xfe) == 0xfc) { /* 31bit */ if (c == 0xfc) { GET_CONT_CHAR (in, i, c); if (!(c & 0x3c)) UTF8_SEQ_ERROR ("0xfc ", c, i - 1, "is a non-shortest form"); cont = 4; } else cont = 5; } else if (c == 0xfe) { /* 36bit */ GET_CONT_CHAR (in, i, c); if (!(c & 0x3e)) UTF8_SEQ_ERROR ("0xfe ", c, i - 1, "is a non-shortest form"); else if (c & 0x3c) UTF8_SEQ_ERROR ("0xfe ", c, i - 1, "would decode to " "a too large character value"); cont = 5; }
be40771998-10-15Henrik Grubbström (Grubba)  }
57dd672005-04-02Martin Stjernholm  if (shift < 2) shift = 2;
be40771998-10-15Henrik Grubbström (Grubba)  }
dee8942005-04-02Martin Stjernholm  while(cont--) GET_CONT_CHAR (in, i, c);
57dd672005-04-02Martin Stjernholm 
6aebbf2012-02-23Henrik Grubbström (Grubba) #undef GET_CHAR
57dd672005-04-02Martin Stjernholm #undef GET_CONT_CHAR #undef UTF8_SEQ_ERROR
be40771998-10-15Henrik Grubbström (Grubba)  } } if (len == in->len) { /* 7bit in == 7bit out */ pop_n_elems(args-1); return; } out = begin_wide_shared_string(len, shift);
57dd672005-04-02Martin Stjernholm  switch (shift) { case 0: {
cfd6422005-04-02Martin Stjernholm  p_wchar0 *out_str = STR0 (out);
cc724f2005-05-05Martin Nilsson  for(i=0; i < in->len;) {
57dd672005-04-02Martin Stjernholm  unsigned int c = STR0(in)[i++]; /* NOTE: No tests here since we've already tested the string above. */ if (c & 0x80) { /* 11bit */ unsigned int c2 = STR0(in)[i++] & 0x3f; c &= 0x1f; c = (c << 6) | c2; } out_str[j++] = c; } break; }
be40771998-10-15Henrik Grubbström (Grubba) 
57dd672005-04-02Martin Stjernholm  case 1: {
cfd6422005-04-02Martin Stjernholm  p_wchar1 *out_str = STR1 (out);
cc724f2005-05-05Martin Nilsson  for(i=0; i < in->len;) {
57dd672005-04-02Martin Stjernholm  unsigned int c = STR0(in)[i++]; /* NOTE: No tests here since we've already tested the string above. */ if (c & 0x80) { if ((c & 0xe0) == 0xc0) { /* 11bit */ unsigned int c2 = STR0(in)[i++] & 0x3f; c &= 0x1f; c = (c << 6) | c2; } else { /* 16bit */ unsigned int c2 = STR0(in)[i++] & 0x3f; unsigned int c3 = STR0(in)[i++] & 0x3f; c &= 0x0f; c = (c << 12) | (c2 << 6) | c3; } } out_str[j++] = c;
be40771998-10-15Henrik Grubbström (Grubba)  }
57dd672005-04-02Martin Stjernholm  break; } case 2: {
cfd6422005-04-02Martin Stjernholm  p_wchar2 *out_str = STR2 (out);
cc724f2005-05-05Martin Nilsson  for(i=0; i < in->len;) {
57dd672005-04-02Martin Stjernholm  unsigned int c = STR0(in)[i++]; /* NOTE: No tests here since we've already tested the string above. */ if (c & 0x80) { int cont = 0; 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 int c2 = STR0(in)[i++] & 0x3f; c = (c << 6) | c2; }
6aebbf2012-02-23Henrik Grubbström (Grubba)  if ((extended & 2) && (c & 0xfc00) == 0xdc00) { /* Low surrogate */ c &= 0x3ff;
9412222012-02-23Henrik Grubbström (Grubba)  c |= ((out_str[--j] & 0x3ff)<<10) + 0x10000;
6aebbf2012-02-23Henrik Grubbström (Grubba)  }
57dd672005-04-02Martin Stjernholm  } out_str[j++] = c;
be40771998-10-15Henrik Grubbström (Grubba)  }
57dd672005-04-02Martin Stjernholm  break;
be40771998-10-15Henrik Grubbström (Grubba)  } }
57dd672005-04-02Martin Stjernholm 
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
be40771998-10-15Henrik Grubbström (Grubba)  if (j != len) {
3686232014-08-18Martin Nilsson  Pike_fatal("Calculated and actual lengths differ: "
2d76f22005-05-20Martin Stjernholm  "%"PRINTPTRDIFFT"d != %"PRINTPTRDIFFT"d\n",
3686232014-08-18Martin Nilsson  len, j);
be40771998-10-15Henrik Grubbström (Grubba)  }
71f3a21998-11-22Fredrik Hübinette (Hubbe) #endif /* PIKE_DEBUG */
57dd672005-04-02Martin Stjernholm  out = low_end_shared_string(out);
cfd6422005-04-02Martin Stjernholm #ifdef PIKE_DEBUG check_string (out); #endif
be40771998-10-15Henrik Grubbström (Grubba)  pop_n_elems(args); push_string(out); }
5845a72018-05-17Henrik Grubbström (Grubba) /*! @decl string validate_utf8(utf8_string s) *! @decl string validate_utf8(utf8_string s, int extended) *! *! Checks whether a string is a valid UTF-8 byte-stream. *! *! @param s *! String of UTF-8 encoded data to validate. *! *! @param extended *! Bitmask with extension options. *! @int *! @value 1
30848b2018-05-18Henrik Grubbström (Grubba)  *! Accept the extension used by @[string_to_utf8()], including *! lone UTF-16 surrogates.
5845a72018-05-17Henrik Grubbström (Grubba)  *! @value 2 *! Accept UTF-8 encoded UTF-16 (ie accept valid surrogate-pairs). *! @endint *! *! @returns *! Returns @expr{0@} (zero) if the stream is not a legal *! UTF-8 byte-stream, and @expr{1@} if it is. *! *! @note *! In conformance with @rfc{3629@} and Unicode 3.1 and later, *! non-shortest forms are considered invalid. *! *! @seealso *! @[Charset.encoder()], @[string_to_unicode()], @[string_to_utf8()], *! @[unicode_to_string()], @[utf8_to_string()] */ PMOD_EXPORT void f_validate_utf8(INT32 args) { struct pike_string *in; ptrdiff_t i; INT_TYPE extended = 0; INT32 min, max; int ret = 1;
30848b2018-05-18Henrik Grubbström (Grubba)  p_wchar1 expect_low_surrogate = 0;
5845a72018-05-17Henrik Grubbström (Grubba)  get_all_args("validate_utf8", args, "%T.%i", &in, &extended); if (in->size_shift) { /* Wide string -- not UTF-8. */ pop_n_elems(args); push_int(0); return; } check_string_range(in, 1, &min, &max); if (min >= 0 && max <= 0x7f) { /* 7bit string -- already valid utf8. */ pop_n_elems(args); push_int(1); return; } for(i=0; ret && (i < in->len); i++) {
30848b2018-05-18Henrik Grubbström (Grubba)  p_wchar0 c = STR0(in)[i]; /* NB: unsigned INT64 to handle bit 33. */ unsigned INT64 ch; unsigned INT64 full_mask = 0x3f; unsigned INT64 hi_mask = 0x3e; /* From table 3-6 in the Unicode standard 4.0: Well-Formed UTF-8 * Byte Sequences * * Code Points 1st Byte 2nd Byte 3rd Byte 4th Byte * 000000-00007f 00-7f * 000080-0007ff c2-df 80-bf * 000800-000fff e0 a0-bf 80-bf * 001000-00cfff e1-ec 80-bf 80-bf * 00d000-00d7ff ed 80-9f 80-bf * 00e000-00ffff ee-ef 80-bf 80-bf * 010000-03ffff f0 90-bf 80-bf 80-bf * 040000-0fffff f1-f3 80-bf 80-bf 80-bf * 100000-10ffff f4 80-8f 80-bf 80-bf */
5845a72018-05-17Henrik Grubbström (Grubba) 
30848b2018-05-18Henrik Grubbström (Grubba)  if (!(c & 0x80)) { if (expect_low_surrogate) ret = 0; /* Expected low surrogate. */ continue; }
5845a72018-05-17Henrik Grubbström (Grubba) 
30848b2018-05-18Henrik Grubbström (Grubba)  if (!(c & 0x40)) { /* Invalid continuation char. */ ret = 0; break; } if (c == 0xff) { /* Invalid UTF-8 code-point. */ ret = 0; break; } ch = c; while (c & 0x40) { /* NB: We rely on the NUL-terminator in pike_strings. */ p_wchar0 cc = STR0(in)[++i]; if ((cc & 0xc0) != 0x80) { /* Expected continuation char. */
5845a72018-05-17Henrik Grubbström (Grubba)  ret = 0; break; }
30848b2018-05-18Henrik Grubbström (Grubba)  ch = ch<<6 | (cc & 0x3f); full_mask |= full_mask << 5; hi_mask <<= 5; c <<= 1; }
5845a72018-05-17Henrik Grubbström (Grubba) 
30848b2018-05-18Henrik Grubbström (Grubba)  ch = ch & full_mask;
5845a72018-05-17Henrik Grubbström (Grubba) 
30848b2018-05-18Henrik Grubbström (Grubba)  if (!(ch & hi_mask) || (ch < 0x80)) { /* The 5 most significant bits of ch are all zero. * This means that it was a non-minimal form. * * Note that a special case is needed for the range 0x40..0x7f. */ ret = 0; break; }
5845a72018-05-17Henrik Grubbström (Grubba) 
30848b2018-05-18Henrik Grubbström (Grubba)  if ((ch & ~0x7ff) == 0xd800) { /* Surrogate */ if (!(extended & 3)) { ret = 0; break;
5845a72018-05-17Henrik Grubbström (Grubba)  }
30848b2018-05-18Henrik Grubbström (Grubba)  if (!(extended & 1) && ((ch & 0x400) != expect_low_surrogate)) { /* Bad surrogate pair. */ ret = 0; break; } expect_low_surrogate = (ch & 0x400) ^ 0x400; } else if (!(extended & 1) && expect_low_surrogate) { ret = 0; break; } else if (ch >= 0x110000) { /* Character out of range. */ if (!(extended & 1) || (ch >= (((unsigned INT64)1) << 32))) { ret = 0; break;
5845a72018-05-17Henrik Grubbström (Grubba)  } } }
30848b2018-05-18Henrik Grubbström (Grubba)  if (!(extended & 1) && expect_low_surrogate) { ret = 0; }
5845a72018-05-17Henrik Grubbström (Grubba)  pop_n_elems(args); push_int(ret); }
f23c5d2007-06-02Martin Bähr /*! @decl string(0..255) __parse_pike_type(string(0..255) 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) 
017b572011-10-28Henrik Grubbström (Grubba)  if( !args || TYPEOF(Pike_sp[-1]) != 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 }
718adc2014-02-24Henrik Grubbström (Grubba) /*! @module Pike */ /*! @decl type soft_cast(type to, type from)
cf27cc2007-04-20Henrik Grubbström (Grubba)  *! *! Return the resulting type from a soft cast of @[from] to @[to]. */ static void f___soft_cast(INT32 args) { struct pike_type *res;
24adc72008-09-26Martin Nilsson  if (args < 2) Pike_error("Bad number of arguments to __soft_cast().\n");
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-args]) != PIKE_T_TYPE) {
24adc72008-09-26Martin Nilsson  Pike_error("Bad argument 1 to __soft_cast() expected type.\n");
cf27cc2007-04-20Henrik Grubbström (Grubba)  }
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[1-args]) != PIKE_T_TYPE) {
24adc72008-09-26Martin Nilsson  Pike_error("Bad argument 2 to __soft_cast() expected type.\n");
cf27cc2007-04-20Henrik Grubbström (Grubba)  } if (!(res = soft_cast(Pike_sp[-args].u.type, Pike_sp[1-args].u.type, 0))) { pop_n_elems(args); push_undefined(); } else { pop_n_elems(args); push_type_value(res); } }
718adc2014-02-24Henrik Grubbström (Grubba) /*! @decl type low_check_call(type fun_type, type arg_type) *! @decl type low_check_call(type fun_type, type arg_type, int flags)
44fe362007-03-26Henrik Grubbström (Grubba)  *! *! Check whether a function of type @[fun_type] may be called *! with a first argument of type @[arg_type]. *!
88d1952007-03-28Henrik Grubbström (Grubba)  *! @param flags *! The following flags are currently defined: *! @int *! @value 1 *! Strict types. Fail if not all possible values in @[arg_type] *! are valid as the first argument to @[fun_type]. *! @value 2 *! Last argument. @[arg_type] is the last argument to @[fun_type]. *! @value 3 *! Both strict types and last argument as above. *! @endint *!
44fe362007-03-26Henrik Grubbström (Grubba)  *! @returns *! Returns a continuation type on success. *! *! Returns @tt{0@} (zero) on failure. */
34d9b52007-03-29Henrik Grubbström (Grubba) static void f___low_check_call(INT32 args)
44fe362007-03-26Henrik Grubbström (Grubba) { struct pike_type *res;
960b402011-12-09Henrik Grubbström (Grubba)  INT32 flags = CALL_NOT_LAST_ARG;
9129122007-04-21Henrik Grubbström (Grubba)  struct svalue *sval = NULL;
34d9b52007-03-29Henrik Grubbström (Grubba)  if (args < 2) Pike_error("Bad number of arguments to __low_check_call().\n");
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-args]) != PIKE_T_TYPE) {
34d9b52007-03-29Henrik Grubbström (Grubba)  Pike_error("Bad argument 1 to __low_check_call() expected type.\n");
44fe362007-03-26Henrik Grubbström (Grubba)  }
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[1-args]) != PIKE_T_TYPE) {
34d9b52007-03-29Henrik Grubbström (Grubba)  Pike_error("Bad argument 2 to __low_check_call() expected type.\n");
88d1952007-03-28Henrik Grubbström (Grubba)  } if (args > 2) {
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[2-args]) != PIKE_T_INT) {
34d9b52007-03-29Henrik Grubbström (Grubba)  Pike_error("Bad argument 3 to __low_check_call() expected int.\n");
88d1952007-03-28Henrik Grubbström (Grubba)  }
960b402011-12-09Henrik Grubbström (Grubba)  flags = Pike_sp[2-args].u.integer ^ CALL_NOT_LAST_ARG;
44fe362007-03-26Henrik Grubbström (Grubba)  }
9129122007-04-21Henrik Grubbström (Grubba)  if (args > 3) sval = Pike_sp + 3 - args;
88d1952007-03-28Henrik Grubbström (Grubba)  if (!(res = low_new_check_call(Pike_sp[-args].u.type,
9129122007-04-21Henrik Grubbström (Grubba)  Pike_sp[1-args].u.type, flags, sval))) {
44fe362007-03-26Henrik Grubbström (Grubba)  pop_n_elems(args); push_undefined(); } else { pop_n_elems(args); push_type_value(res); } }
718adc2014-02-24Henrik Grubbström (Grubba) /*! @decl type get_return_type(type fun_type)
44fe362007-03-26Henrik Grubbström (Grubba)  *! *! Check what a function of the type @[fun_type] will *! return if called with no arguments. *! *! @returns *! Returns the type of the returned value on success *! *! Returns @tt{0@} (zero) on failure. */ static void f___get_return_type(INT32 args) { struct pike_type *res; if (args != 1) { Pike_error("Bad number of arguments to __get_return_type().\n"); }
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-1]) != PIKE_T_TYPE) {
44fe362007-03-26Henrik Grubbström (Grubba)  Pike_error("Bad argument 1 to __get_return_type() expected type.\n"); } if (!(res = new_get_return_type(Pike_sp[-1].u.type, 0))) { pop_n_elems(args); push_undefined(); } else { pop_n_elems(args); push_type_value(res); } }
718adc2014-02-24Henrik Grubbström (Grubba) /*! @decl type get_first_arg_type(type fun_type)
44fe362007-03-26Henrik Grubbström (Grubba)  *! *! Check if a function of the type @[fun_type] may be called *! with an argument, and return the type of that argument. *! *! @returns *! Returns the expected type of the first argument to the function. *! *! Returns @tt{0@} (zero) if a function of the type @[fun_type] *! may not be called with any argument, or if it is not callable. */
c914682014-04-07Henrik Grubbström (Grubba) void f___get_first_arg_type(INT32 args)
44fe362007-03-26Henrik Grubbström (Grubba) { struct pike_type *res; if (args != 1) { Pike_error("Bad number of arguments to __get_first_arg_type().\n"); }
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-1]) != PIKE_T_TYPE) {
44fe362007-03-26Henrik Grubbström (Grubba)  Pike_error("Bad argument 1 to __get_first_arg_type() expected type.\n"); }
301daf2011-12-09Henrik Grubbström (Grubba)  if (!(res = get_first_arg_type(Pike_sp[-1].u.type, CALL_NOT_LAST_ARG)) && !(res = get_first_arg_type(Pike_sp[-1].u.type, 0))) {
44fe362007-03-26Henrik Grubbström (Grubba)  pop_n_elems(args); push_undefined(); } else { pop_n_elems(args); push_type_value(res); } }
718adc2014-02-24Henrik Grubbström (Grubba) /*! @decl array(string) get_type_attributes(type t)
a54cfc2011-01-17Henrik Grubbström (Grubba)  *! *! Get the attribute markers for a type. *! *! @returns *! Returns an array with the attributes for the type @[t]. *! *! @seealso
718adc2014-02-24Henrik Grubbström (Grubba)  *! @[get_return_type()], @[get_first_arg_type()]
a54cfc2011-01-17Henrik Grubbström (Grubba)  */ static void f___get_type_attributes(INT32 args) { struct pike_type *t; int count = 0; if (args != 1) { Pike_error("Bad number of arguments to __get_type_attributes().\n"); }
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-1]) != PIKE_T_TYPE) {
a54cfc2011-01-17Henrik Grubbström (Grubba)  Pike_error("Bad argument 1 to __get_type_attributes() expected type.\n"); } t = Pike_sp[-1].u.type; /* Note: We assume that the set of attributes is small * enough that we won't run out of stack. */ while ((t->type == PIKE_T_ATTRIBUTE) || (t->type == PIKE_T_NAME)) { if (t->type == PIKE_T_ATTRIBUTE) { ref_push_string((struct pike_string *)t->car); count++; } t = t->cdr; } f_aggregate(count); stack_pop_n_elems_keep_top(args); }
718adc2014-02-24Henrik Grubbström (Grubba) /*! @endmodule Pike */
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) }
200e5f2018-07-18Henrik Grubbström (Grubba) /*! @decl CompilerEnvironment.PikeCompiler get_active_compiler() *! *! Returns the most recent of the currently active pike compilers, *! or @[UNDEFINED] if none is active. *! *! @note *! This function should only be used during a call of @[compile()]. *! *! @seealso *! @[get_active_error_handler()], @[compile()], *! @[master()->get_compilation_handler()], @[CompilationHandler] */ PMOD_EXPORT void f_get_active_compiler(INT32 args) { struct compilation *c = NULL; /* NB: This is an efun, so we need to keep the stack clean. */ pop_n_elems(args); if (compilation_program) { struct pike_frame *compiler_frame = Pike_fp; while (compiler_frame && (compiler_frame->context->prog != compilation_program)) { compiler_frame = compiler_frame->next; } if (compiler_frame && compiler_frame->current_object->prog) { ref_push_object(compiler_frame->current_object); return; } } push_undefined(); }
e290f32006-01-27Henrik Grubbström (Grubba) /*! @decl CompilationHandler get_active_compilation_handler()
5671ce2006-01-26Henrik Grubbström (Grubba)  *! *! Returns the currently active compilation compatibility handler, or *! @tt{0@} (zero) if none is active. *! *! @note *! This function should only be used during a call of @[compile()]. *! *! @seealso *! @[get_active_error_handler()], @[compile()],
e290f32006-01-27Henrik Grubbström (Grubba)  *! @[master()->get_compilation_handler()], @[CompilationHandler]
5671ce2006-01-26Henrik Grubbström (Grubba)  */ PMOD_EXPORT void f_get_active_compilation_handler(INT32 args) {
e021fe2008-04-14Henrik Grubbström (Grubba)  struct compilation *c = NULL; if (compilation_program) { struct pike_frame *compiler_frame = Pike_fp; while (compiler_frame && (compiler_frame->context->prog != compilation_program)) { compiler_frame = compiler_frame->next; } if (compiler_frame) { c = (struct compilation *)compiler_frame->current_storage; } }
13670c2015-05-25Martin Nilsson 
5671ce2006-01-26Henrik Grubbström (Grubba)  pop_n_elems(args);
e021fe2008-04-14Henrik Grubbström (Grubba)  if (c && c->compat_handler) { ref_push_object(c->compat_handler);
5671ce2006-01-26Henrik Grubbström (Grubba)  } else { push_int(0); } }
e290f32006-01-27Henrik Grubbström (Grubba) /*! @decl CompilationHandler get_active_error_handler()
5671ce2006-01-26Henrik Grubbström (Grubba)  *! *! Returns the currently active compilation error handler
e290f32006-01-27Henrik Grubbström (Grubba)  *! (second argument to @[compile()]), or @tt{0@} (zero) if none
5671ce2006-01-26Henrik Grubbström (Grubba)  *! is active. *! *! @note *! This function should only be used during a call of @[compile()]. *! *! @seealso
e290f32006-01-27Henrik Grubbström (Grubba)  *! @[get_active_compilation_handler()], @[compile()], @[CompilationHandler]
5671ce2006-01-26Henrik Grubbström (Grubba)  */ PMOD_EXPORT void f_get_active_error_handler(INT32 args) {
e021fe2008-04-14Henrik Grubbström (Grubba)  struct compilation *c = NULL; if (compilation_program) { struct pike_frame *compiler_frame = Pike_fp; while (compiler_frame && (compiler_frame->context->prog != compilation_program)) { compiler_frame = compiler_frame->next; } if (compiler_frame) { c = (struct compilation *)compiler_frame->current_storage; } }
13670c2015-05-25Martin Nilsson 
5671ce2006-01-26Henrik Grubbström (Grubba)  pop_n_elems(args);
e021fe2008-04-14Henrik Grubbström (Grubba)  if (c && c->handler) { ref_push_object(c->handler);
5671ce2006-01-26Henrik Grubbström (Grubba)  } else { push_int(0); } }
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) {
3ee2a62004-11-14Alexander Demenshin  INT_TYPE size;
8267f41998-01-28Fredrik Hübinette (Hubbe)  struct array *a;
e6c0892010-07-27Martin Stjernholm  struct svalue *init = NULL;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
87a3422004-05-13Martin Nilsson  get_all_args("allocate", args, "%+.%*", &size, &init);
2cff8d2004-11-14Martin Stjernholm  if (size > MAX_INT32) SIMPLE_ARG_ERROR ("allocate", 1, "Integer too large to use as array size.");
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);
e6c0892010-07-27Martin Stjernholm  if (init) { for(e=0;e<size;e++) copy_svalues_recursively_no_free(a->item+e, init, 1, 0);
017b572011-10-28Henrik Grubbström (Grubba)  a->type_field = 1 << TYPEOF(*init);
e6c0892010-07-27Martin Stjernholm  } else { /* It's somewhat quirky that allocate(17) and allocate(17, UNDEFINED) * have different behavior, but it's of some use, and it's compatible * with previous versions. */ for(e=0;e<size;e++) ITEM (a)[e] = svalue_undefined; a->type_field = BIT_INT; }
2523ce2003-04-28Martin Stjernholm  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  *!
4f44a42015-06-18Henrik Grubbström (Grubba)  *! @param level *! @[level] may be used to access the object of a surrounding
0ee38f2002-05-11Martin Stjernholm  *! 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) {
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-args]) != T_INT || Pike_sp[-args].u.integer < 0)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR ("this_object", 1, "a non-negative integer");
0ee38f2002-05-11Martin Stjernholm  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)) {
8853882008-04-26Henrik Grubbström (Grubba)  struct compilation *c = THIS_COMPILATION;
0ee38f2002-05-11Martin Stjernholm  struct program_state *state = Pike_compiler;
8853882008-04-26Henrik Grubbström (Grubba)  CHECK_COMPILER();
0ee38f2002-05-11Martin Stjernholm  if (CDR (n)->token != F_CONSTANT) { /* Not a constant expression. Make sure there are parent * pointers all the way. */ int i;
8853882008-04-26Henrik Grubbström (Grubba)  for (i = 0; i < c->compilation_depth; i++, state = state->previous)
0ee38f2002-05-11Martin Stjernholm  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
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(CDR(n)->u.sval) != 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;
8853882008-04-26Henrik Grubbström (Grubba)  for (i = MINIMUM(level, c->compilation_depth); i;
073ccf2003-08-04Henrik Grubbström (Grubba)  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;
e021fe2008-04-14Henrik Grubbström (Grubba)  struct compilation *c = THIS_COMPILATION; CHECK_COMPILER();
0ee38f2002-05-11Martin Stjernholm  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
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(CDR(n)->u.sval) != 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);
384f222008-08-28Henrik Grubbström (Grubba)  modify_stack_depth(1);
0811472001-07-02Fredrik Hübinette (Hubbe)  return 1; }
bf5cbe2005-02-18Henrik Grubbström (Grubba) /*! @decl mixed|void throw(mixed value)
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
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) {
06bd612016-01-26Martin Nilsson  if(args != 1) SIMPLE_WRONG_NUM_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) }
ba58572008-07-09Henrik Grubbström (Grubba) int in_forked_child = 0;
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 
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(args < 1)
06bd612016-01-26Martin Nilsson  SIMPLE_WRONG_NUM_ARGS_ERROR("exit", 1);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[-args]) != T_INT)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_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;
017b572011-10-28Henrik Grubbström (Grubba)  if(args>1 && TYPEOF(Pike_sp[1-args]) == T_STRING) {
ea84872007-01-15Henrik Grubbström (Grubba)  struct svalue *s = simple_mapping_string_lookup(get_builtin_constants(), "werror"); if (s) { apply_svalue(s, args-1); pop_stack();
7f69142007-01-15Henrik Grubbström (Grubba)  } else {
ea84872007-01-15Henrik Grubbström (Grubba)  fprintf(stderr, "No efun::werror() at exit.\n"); pop_n_elems(args-1); }
d8e90a2004-05-09Martin Nilsson  args=1; }
b5ef7d2004-01-11Martin Nilsson 
ba58572008-07-09Henrik Grubbström (Grubba)  if (in_forked_child) { /* Don't bother to clean up if we're running in a forked child. */ f__exit(args); }
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 
d9ed862005-11-19Henrik Grubbström (Grubba)  get_all_args("_exit", args, "%d", &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
ba58572008-07-09Henrik Grubbström (Grubba)  /* FIXME: Shouldn't _exit(2) be called here? */
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
98c6022017-11-01Stephen R. van den Berg  *! time, instead the last time value used by the pike process is returned *! again. It avoids a system call, and thus is slightly faster, *! but can be wildly inaccurate. Pike
93af2d2003-10-31Martin Stjernholm  *! 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)  *!
98c6022017-11-01Stephen R. van den Berg  *! The third syntax can be used to measure time more precisely than one *! second. It returns how many seconds have passed since @[t]. The precision
554e222001-05-06Henrik Grubbström (Grubba)  *! of this function varies from system to system.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
5ef9052003-01-13Martin Stjernholm  *! @[ctime()], @[localtime()], @[mktime()], @[gmtime()],
87d5d42018-02-09Stephen R. van den Berg  *! @[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) {
f010202011-11-16Tobias S. Josefowitz  struct timeval ret;
017b572011-10-28Henrik Grubbström (Grubba)  if(!args || (TYPEOF(Pike_sp[-args]) == T_INT && Pike_sp[-args].u.integer == 0))
d0e6741998-07-15Fredrik Hübinette (Hubbe)  {
f010202011-11-16Tobias S. Josefowitz  ACCURATE_GETTIMEOFDAY(&ret); pop_n_elems(args); push_int(ret.tv_sec); return;
d0e6741998-07-15Fredrik Hübinette (Hubbe)  }else{
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[-args]) == T_INT && Pike_sp[-args].u.integer > 1)
d0e6741998-07-15Fredrik Hübinette (Hubbe)  { struct timeval tmp;
f010202011-11-16Tobias S. Josefowitz  ACCURATE_GETTIMEOFDAY(&ret);
edf4d02000-07-06Fredrik Hübinette (Hubbe)  tmp.tv_sec=Pike_sp[-args].u.integer;
d0e6741998-07-15Fredrik Hübinette (Hubbe)  tmp.tv_usec=0;
f010202011-11-16Tobias S. Josefowitz  my_subtract_timeval(&tmp,&ret);
d0e6741998-07-15Fredrik Hübinette (Hubbe)  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);
f010202011-11-16Tobias S. Josefowitz  INACCURATE_GETTIMEOFDAY(&ret); push_int(ret.tv_sec);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
e911d62016-07-25Martin Nilsson /*! @decl string(46..122) crypt(string(1..255) password) *! @decl int(0..1) crypt(string(1..255) input_password, @ *! string(46..122) crypted_password)
aa5f992016-12-08Martin Nilsson  *! @decl string(46..122) crypt()
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
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  *!
aa5f992016-12-08Martin Nilsson  *! The third syntax generates a random string and then crypts it, *! creating a string useful as a password. *!
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];
43c7732016-12-10Martin Nilsson  char *ret, *pwd = NULL, *saltp = NULL;
a913232016-03-12Martin Nilsson  char *alphabet = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
5267b71995-08-09Fredrik Hübinette (Hubbe) 
aa5f992016-12-08Martin Nilsson  get_all_args("crypt", args, ".%s%s", &pwd, &saltp); if( !pwd ) { do { push_random_string(16); push_constant_text("\0"); f_minus(2); } while(Pike_sp[-1].u.string->len<8);
43c7732016-12-10Martin Nilsson  pwd = Pike_sp[-1].u.string->str;
a669462018-06-07Henrik Grubbström (Grubba)  args++;
aa5f992016-12-08Martin Nilsson  }
5267b71995-08-09Fredrik Hübinette (Hubbe) 
ddc1a32010-07-27Martin Stjernholm  if(saltp)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
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 {
a913232016-03-12Martin Nilsson  struct svalue *random = simple_mapping_string_lookup(get_builtin_constants(), "random"); if(!random || (TYPEOF(*random) != T_FUNCTION)) Pike_error("Unable to resolve random function.\n"); push_int(4096); /* strlen(alphbet)**2 */
2f6a602016-03-12Martin Nilsson  apply_svalue(random, 1);
a913232016-03-12Martin Nilsson  if(TYPEOF(Pike_sp[-1])!=T_INT) Pike_error("Couldn't generate random number.\n"); salt[0] = alphabet[ Pike_sp[-1].u.integer & 0x3f ]; salt[1] = alphabet[ (Pike_sp[-1].u.integer>>6) & 0x3f ];
2f6a602016-03-12Martin Nilsson  pop_stack();
a913232016-03-12Martin Nilsson 
8beaf71996-04-13Fredrik Hübinette (Hubbe)  saltp=salt;
44e09d2011-11-24Henrik Grubbström (Grubba)  if (args > 1) { pop_n_elems(args-1); args = 1; }
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
24adc72008-09-26Martin Nilsson #error No crypt function found and fallback failed.
5267b71995-08-09Fredrik Hübinette (Hubbe) #endif #endif
95b2f82011-06-29Henrik Grubbström (Grubba)  if (!ret) { switch(errno) { #ifdef ELIBACC case ELIBACC: Pike_error("Failed to load a required shared library. " "Unsupported salt.\n"); break; #endif case ENOMEM: Pike_error("Out of memory.\n"); break; case EINVAL: default: Pike_error("Unsupported salt (%d).\n", errno); break; } }
5267b71995-08-09Fredrik Hübinette (Hubbe)  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)  *!
f76ace2017-11-05Henrik Grubbström (Grubba)  *! Calls @expr{o->_destruct()@}, and then clears all variables in the
c8bb3c2004-04-20Martin Nilsson  *! 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.
13670c2015-05-25Martin Nilsson  */
1f21332000-07-28Fredrik Hübinette (Hubbe) PMOD_EXPORT void f_destruct(INT32 args)
5267b71995-08-09Fredrik Hübinette (Hubbe) { struct object *o; if(args) {
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[-args]) != T_OBJECT) { if ((TYPEOF(Pike_sp[-args]) == T_INT) &&
b5d71b2001-06-09Henrik Grubbström (Grubba)  (!Pike_sp[-args].u.integer)) { pop_n_elems(args); return; }
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_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);
54717e2001-06-28Fredrik Hübinette (Hubbe)  debug_malloc_touch(o);
09f2882005-02-09Martin Stjernholm  destruct_object (o, DESTRUCT_EXPLICIT);
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)  *!
55d1342015-06-26Henrik Grubbström (Grubba)  *! @param x *! @mixed *! @type string *! @type array *! For strings and arrays this is simply an array of ascending *! numbers.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
55d1342015-06-26Henrik Grubbström (Grubba)  *! @type mapping *! @type multiset *! For mappings and multisets, the array might contain any value.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
55d1342015-06-26Henrik Grubbström (Grubba)  *! @type object *! For objects which define @[lfun::_indices()] that return value *! is used.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
55d1342015-06-26Henrik Grubbström (Grubba)  *! For other objects an array with the names of all non-protected *! symbols is returned. *! @endmixed
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
7195af2011-01-15Henrik Grubbström (Grubba)  *! @[values()], @[types()], @[lfun::_indices()]
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) 
06bd612016-01-26Martin Nilsson  if(args != 1) SIMPLE_WRONG_NUM_ARGS_ERROR("indices", 1);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
017b572011-10-28Henrik Grubbström (Grubba)  switch(TYPEOF(Pike_sp[-args]))
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. */
bd67392015-10-14Martin Nilsson  ITEM(a)[size].u.integer = (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:
017b572011-10-28Henrik Grubbström (Grubba)  a=object_indices(Pike_sp[-args].u.object, SUBTYPEOF(Pike_sp[-args]));
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; } }
ff2bc92018-02-15Martin Nilsson  /* FALLTHRU */
0ceb871998-06-07Henrik Grubbström (Grubba) 
5267b71995-08-09Fredrik Hübinette (Hubbe)  default:
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("indices", 1, "string|array|mapping|" "multiset|object|program|function");
5267b71995-08-09Fredrik Hübinette (Hubbe)  } 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. */
74dfe82012-12-30Jonas Walldén static node *fix_overloaded_type(node *n, int lfun, const char *deftype, int UNUSED(deftypelen))
4d7b181999-12-07Fredrik Hübinette (Hubbe) { 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; } } }
13670c2015-05-25Martin Nilsson  /* If it is an object, it *may* be overloaded, we or with
4d7b181999-12-07Fredrik Hübinette (Hubbe)  * 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 }
13670c2015-05-25Martin Nilsson 
4d7b181999-12-07Fredrik Hübinette (Hubbe)  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;
5632b62017-11-04Arne Goedeke  /* Handle the special case where CAR & CDR are the same. */
f01a891999-12-08Henrik Grubbström (Grubba)  } 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;
13670c2015-05-25Martin Nilsson  }
aab8411999-12-07Henrik Grubbström (Grubba)  } 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)  *!
55d1342015-06-26Henrik Grubbström (Grubba)  *! @param x *! @mixed *! @type string *! For strings an array of int with the ISO10646 codes of the *! characters in the string is returned.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
55d1342015-06-26Henrik Grubbström (Grubba)  *! @type multiset *! For a multiset an array filled with ones (@expr{1@}) is *! returned.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
55d1342015-06-26Henrik Grubbström (Grubba)  *! @type array *! For arrays a single-level copy of @[x] is returned.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
55d1342015-06-26Henrik Grubbström (Grubba)  *! @type mapping *! For mappings the array may contain any value.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
55d1342015-06-26Henrik Grubbström (Grubba)  *! @type object *! For objects which define @[lfun::_values()] that return value *! is used.
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *!
55d1342015-06-26Henrik Grubbström (Grubba)  *! For other objects an array with the values of all non-protected *! symbols is returned. *! @endmixed
9c1a7b2001-01-08Henrik Grubbström (Grubba)  *! *! @seealso
7195af2011-01-15Henrik Grubbström (Grubba)  *! @[indices()], @[types()], @[lfun::_values()]
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;
06bd612016-01-26Martin Nilsson  if(args != 1) SIMPLE_WRONG_NUM_ARGS_ERROR("values", 1);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
017b572011-10-28Henrik Grubbström (Grubba)  switch(TYPEOF(Pike_sp[-args]))
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:
017b572011-10-28Henrik Grubbström (Grubba)  a=object_values(Pike_sp[-args].u.object, SUBTYPEOF(Pike_sp[-args]));
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; } }
ff2bc92018-02-15Martin Nilsson  /* FALLTHRU */
0ceb871998-06-07Henrik Grubbström (Grubba) 
5267b71995-08-09Fredrik Hübinette (Hubbe)  default:
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("values", 1, "string|array|mapping|multiset|" "object|program|function");
5267b71995-08-09Fredrik Hübinette (Hubbe)  } pop_n_elems(args); push_array(a); }
7195af2011-01-15Henrik Grubbström (Grubba) /*! @decl array(type(mixed)) types(string|array|mapping|multiset|object x) *!
55d1342015-06-26Henrik Grubbström (Grubba)  *! Return an array with the types of all valid indices for the value @[x].
7195af2011-01-15Henrik Grubbström (Grubba)  *!
55d1342015-06-26Henrik Grubbström (Grubba)  *! @param x *! @mixed *! @type string *! For strings this is simply an array with @tt{int@}
7195af2011-01-15Henrik Grubbström (Grubba)  *!
55d1342015-06-26Henrik Grubbström (Grubba)  *! @type array *! @type mapping *! @type multiset *! For arrays, mappings and multisets this is simply *! an array with @tt{mixed@}.
7195af2011-01-15Henrik Grubbström (Grubba)  *!
55d1342015-06-26Henrik Grubbström (Grubba)  *! @type object *! For objects which define @[lfun::_types()] that return value *! is used.
7195af2011-01-15Henrik Grubbström (Grubba)  *!
55d1342015-06-26Henrik Grubbström (Grubba)  *! For other objects an array with type types for all non-protected *! symbols is returned. *! @endmixed
7195af2011-01-15Henrik Grubbström (Grubba)  *! *! @note *! This function was added in Pike 7.9. *! *! @seealso *! @[indices()], @[values()], @[lfun::_types()] */ PMOD_EXPORT void f_types(INT32 args) { ptrdiff_t size; struct array *a = NULL; struct pike_type *default_type = mixed_type_string;
06bd612016-01-26Martin Nilsson  if(args != 1) SIMPLE_WRONG_NUM_ARGS_ERROR("types", 1);
7195af2011-01-15Henrik Grubbström (Grubba) 
017b572011-10-28Henrik Grubbström (Grubba)  switch(TYPEOF(Pike_sp[-args]))
7195af2011-01-15Henrik Grubbström (Grubba)  { case T_STRING: default_type = int_type_string; size=Pike_sp[-args].u.string->len; goto qjump; case T_MAPPING: size = Pike_sp[-args].u.mapping->data->size; goto qjump; case T_MULTISET: /* FIXME: Ought to be int(1..1). */ default_type = int_type_string; size = Pike_sp[-args].u.multiset->msd->size; goto qjump; case T_ARRAY: size=Pike_sp[-args].u.array->size; qjump: a=allocate_array_no_init(size,0); while(--size>=0) { /* Elements are already integers. */
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(ITEM(a)[size], PIKE_T_TYPE, 0, type, default_type); add_ref(default_type);
7195af2011-01-15Henrik Grubbström (Grubba)  } a->type_field = BIT_TYPE; break; case T_OBJECT:
017b572011-10-28Henrik Grubbström (Grubba)  a=object_types(Pike_sp[-args].u.object, SUBTYPEOF(Pike_sp[-args]));
7195af2011-01-15Henrik Grubbström (Grubba)  break; case T_PROGRAM: a = program_types(Pike_sp[-args].u.program); break; case T_FUNCTION: { struct program *p = program_from_svalue(Pike_sp-args); if (p) { a = program_types(p); break; } }
ff2bc92018-02-15Martin Nilsson  /* FALLTHRU */
7195af2011-01-15Henrik Grubbström (Grubba)  default:
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("types", 1, "string|array|mapping|" "multiset|object|program|function");
7195af2011-01-15Henrik Grubbström (Grubba)  } pop_n_elems(args); push_array(a); }
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) {
06bd612016-01-26Martin Nilsson  if(args != 1) SIMPLE_WRONG_NUM_ARGS_ERROR("object_program", 1);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[-args]) == 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(p)
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  {
017b572011-10-28Henrik Grubbström (Grubba)  if (SUBTYPEOF(Pike_sp[-args])) {
d22ebc2008-05-28Henrik Grubbström (Grubba)  /* FIXME: This probably works for the subtype-less case as well. */ struct external_variable_context loc; loc.o = o;
017b572011-10-28Henrik Grubbström (Grubba)  p = (loc.inherit = p->inherits + SUBTYPEOF(Pike_sp[-args]))->prog;
d22ebc2008-05-28Henrik Grubbström (Grubba)  if (p->flags & PROGRAM_USES_PARENT) { loc.parent_identifier = loc.inherit->parent_identifier; find_external_context(&loc, 1); add_ref(loc.o); pop_n_elems(args); push_function(loc.o, loc.parent_identifier); return; }
13670c2015-05-25Martin Nilsson  } else if((p->flags & PROGRAM_USES_PARENT) &&
f3c7152001-04-14Fredrik Hübinette (Hubbe)  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; }
d22ebc2008-05-28Henrik Grubbström (Grubba)  add_ref(p); pop_n_elems(args); push_program(p); return;
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  }
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; }
2b888e2008-01-29Henrik Grubbström (Grubba) /*! @decl string reverse(string s, int|void start, int|void end) *! @decl array reverse(array a, int|void start, int|void end) *! @decl int reverse(int i, int|void start, int|void end)
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Reverses a string, array or int.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
2b888e2008-01-29Henrik Grubbström (Grubba)  *! @param s *! String to reverse. *! @param a *! Array to reverse. *! @param i *! Integer to reverse. *! @param start *! Optional start index of the range to reverse. *! Default: @expr{0@} (zero). *! @param end *! Optional end index of the range to reverse. *! Default for strings: @expr{sizeof(s)-1@}. *! Default for arrays: @expr{sizeof(a)-1@}. *! Default for integers: @expr{Pike.get_runtime_info()->int_size - 1@}. *!
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) {
2b888e2008-01-29Henrik Grubbström (Grubba)  struct svalue *sv; int start = 0, end = -1;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
2b888e2008-01-29Henrik Grubbström (Grubba)  get_all_args("reverse", args, "%*.%d%d", &sv, &start, &end);
017b572011-10-28Henrik Grubbström (Grubba)  switch(TYPEOF(*sv))
5267b71995-08-09Fredrik Hübinette (Hubbe)  { case T_STRING: { INT32 e;
06983f1996-09-22Fredrik Hübinette (Hubbe)  struct pike_string *s;
0ede072008-08-22Henrik Grubbström (Grubba)  struct pike_string *orig = sv->u.string;;
2b888e2008-01-29Henrik Grubbström (Grubba)  if (start < 0) { start = 0;
0ede072008-08-22Henrik Grubbström (Grubba)  } else if (start >= orig->len) {
2b888e2008-01-29Henrik Grubbström (Grubba)  /* Noop. */ pop_n_elems(args-1); break; }
0ede072008-08-22Henrik Grubbström (Grubba)  if ((end < 0) || (end >= orig->len)) { end = orig->len;
2b888e2008-01-29Henrik Grubbström (Grubba)  } else if (end <= start) { /* Noop. */ pop_n_elems(args-1); break; } else { end++; }
0ede072008-08-22Henrik Grubbström (Grubba)  s=begin_wide_shared_string(orig->len, orig->size_shift); if ((orig->len << orig->size_shift) >= 524288) { /* More than 512KB. Release the interpreter lock. */ THREADS_ALLOW(); switch(orig->size_shift) { case 0: for(e=0;e<start;e++) STR0(s)[e]=STR0(orig)[e]; for(;e<end;e++) STR0(s)[e]=STR0(orig)[end-1-e-start]; for(;e<orig->len;e++) STR0(s)[e]=STR0(orig)[e]; break; case 1: for(e=0;e<start;e++) STR1(s)[e]=STR1(orig)[e]; for(;e<end;e++) STR1(s)[e]=STR1(orig)[end-1-e-start]; for(;e<orig->len;e++) STR1(s)[e]=STR1(orig)[e]; break; case 2: for(e=0;e<start;e++) STR2(s)[e]=STR2(orig)[e]; for(;e<end;e++) STR2(s)[e]=STR2(orig)[end-1-e-start]; for(;e<orig->len;e++) STR2(s)[e]=STR2(orig)[e]; break; } THREADS_DISALLOW(); } else { switch(orig->size_shift) {
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  case 0:
2b888e2008-01-29Henrik Grubbström (Grubba)  for(e=0;e<start;e++)
0ede072008-08-22Henrik Grubbström (Grubba)  STR0(s)[e]=STR0(orig)[e];
2b888e2008-01-29Henrik Grubbström (Grubba)  for(;e<end;e++)
0ede072008-08-22Henrik Grubbström (Grubba)  STR0(s)[e]=STR0(orig)[end-1-e-start]; for(;e<orig->len;e++) STR0(s)[e]=STR0(orig)[e];
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  break; case 1:
2b888e2008-01-29Henrik Grubbström (Grubba)  for(e=0;e<start;e++)
0ede072008-08-22Henrik Grubbström (Grubba)  STR1(s)[e]=STR1(orig)[e];
2b888e2008-01-29Henrik Grubbström (Grubba)  for(;e<end;e++)
0ede072008-08-22Henrik Grubbström (Grubba)  STR1(s)[e]=STR1(orig)[end-1-e-start]; for(;e<orig->len;e++) STR1(s)[e]=STR1(orig)[e];
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  break; case 2:
2b888e2008-01-29Henrik Grubbström (Grubba)  for(e=0;e<start;e++)
0ede072008-08-22Henrik Grubbström (Grubba)  STR2(s)[e]=STR2(orig)[e];
2b888e2008-01-29Henrik Grubbström (Grubba)  for(;e<end;e++)
0ede072008-08-22Henrik Grubbström (Grubba)  STR2(s)[e]=STR2(orig)[end-1-e-start]; for(;e<orig->len;e++) STR2(s)[e]=STR2(orig)[e];
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  break;
0ede072008-08-22Henrik Grubbström (Grubba)  }
0bc4cf1998-10-13Fredrik Hübinette (Hubbe)  } s=low_end_shared_string(s);
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_string(s); break; } case T_INT: {
2b888e2008-01-29Henrik Grubbström (Grubba)  /* FIXME: Ought to use INT_TYPE! */
5267b71995-08-09Fredrik Hübinette (Hubbe)  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: {
2b888e2008-01-29Henrik Grubbström (Grubba)  struct array *a = sv->u.array; a = reverse_array(a, start, (end < 0)?a->size:end);
5267b71995-08-09Fredrik Hübinette (Hubbe)  pop_n_elems(args); push_array(a); break; } default:
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("reverse", 1, "string|int|array");
5267b71995-08-09Fredrik Hübinette (Hubbe)  } }
7e97c31999-01-21Fredrik Hübinette (Hubbe) /* Magic, magic and more magic */
3f268a2006-03-09Henrik Grubbström (Grubba) /* Returns the index in v for the string that is the longest prefix of * str (if any). * * v is the sorted (according to generic_quick_binary_strcmp()) vector * of replacement strings. It also has the prefix forest identified. * * a is the lower bound. * b is the upper bound + 1. */
dc384d2006-03-11Henrik Grubbström (Grubba) int find_longest_prefix(char *str, ptrdiff_t len, int size_shift, struct replace_many_tupel *v, INT32 a, INT32 b)
7e97c31999-01-21Fredrik Hübinette (Hubbe) {
66096f2008-07-04Martin Stjernholm  INT32 c, match=-1, match_len=-1;
93b7202000-08-14Henrik Grubbström (Grubba)  ptrdiff_t tmp;
0fe6702004-04-30Martin Stjernholm  check_c_stack(2048);
7e97c31999-01-21Fredrik Hübinette (Hubbe)  while(a<b) { c=(a+b)/2;
3f268a2006-03-09Henrik Grubbström (Grubba) 
24e45c2006-03-11Henrik Grubbström (Grubba)  if (v[c].ind->len <= match_len) { /* Can't be a suffix of (or is equal to) the current match. */ b = c; continue; }
18d9352006-03-10Henrik Grubbström (Grubba)  tmp=generic_find_binary_prefix(v[c].ind->str, v[c].ind->len, v[c].ind->size_shift, str, MINIMUM(len,v[c].ind->len), size_shift);
d8fc6f2006-03-10Henrik Grubbström (Grubba) 
7e97c31999-01-21Fredrik Hübinette (Hubbe)  if(tmp<0) {
18d9352006-03-10Henrik Grubbström (Grubba)  /* Check if we might have a valid prefix that is better than * the current match. */ if (~tmp > match_len) {
3f268a2006-03-09Henrik Grubbström (Grubba)  /* We need to look closer to see if we might have a partial prefix. */ int d = c;
18d9352006-03-10Henrik Grubbström (Grubba)  tmp = -tmp; while (((d = v[d].prefix) >= a) && (v[d].ind->len > match_len)) { if (v[d].ind->len < tmp) {
3f268a2006-03-09Henrik Grubbström (Grubba)  /* Found a valid prefix. */ match = d; match_len = v[d].ind->len; break; }
7e97c31999-01-21Fredrik Hübinette (Hubbe)  } }
3f268a2006-03-09Henrik Grubbström (Grubba)  a = c+1;
7e97c31999-01-21Fredrik Hübinette (Hubbe)  } else if(tmp>0) { b=c;
28ab942006-03-13Henrik Grubbström (Grubba)  while ((c = v[b].prefix) > a) { if (v[c].ind->len < tmp) { if (v[c].ind->len > match_len) { match = c; match_len = v[c].ind->len; } a = c+1; break; } b = c; }
7e97c31999-01-21Fredrik Hübinette (Hubbe)  } else {
24e45c2006-03-11Henrik Grubbström (Grubba)  if (!v[c].is_prefix) { return c; }
7e97c31999-01-21Fredrik Hübinette (Hubbe)  a=c+1; /* There might still be a better match... */ match=c;
3f268a2006-03-09Henrik Grubbström (Grubba)  match_len = v[c].ind->len;
7e97c31999-01-21Fredrik Hübinette (Hubbe)  } } return match; }
13670c2015-05-25Martin Nilsson 
7e97c31999-01-21Fredrik Hübinette (Hubbe) 
dc384d2006-03-11Henrik Grubbström (Grubba) static int replace_sortfun(struct replace_many_tupel *a, struct replace_many_tupel *b)
70da5a2001-06-27Henrik Grubbström (Grubba) {
bd67392015-10-14Martin Nilsson  return (int)my_quick_strcmp(a->ind, b->ind);
70da5a2001-06-27Henrik Grubbström (Grubba) }
dc384d2006-03-11Henrik Grubbström (Grubba) void free_replace_many_context(struct replace_many_context *ctx)
0fe6702004-04-30Martin Stjernholm {
dc384d2006-03-11Henrik Grubbström (Grubba)  if (ctx->v) { if (ctx->flags) { /* Used for the precompiled case. */ int e = ctx->num; while (e--) { free_string(ctx->v[e].ind); free_string(ctx->v[e].val); } if (ctx->empty_repl) { free_string(ctx->empty_repl); } }
0ec7522014-04-27Martin Nilsson  free (ctx->v);
dc384d2006-03-11Henrik Grubbström (Grubba)  ctx->v = NULL; }
0fe6702004-04-30Martin Stjernholm }
dc384d2006-03-11Henrik Grubbström (Grubba) void compile_replace_many(struct replace_many_context *ctx, struct array *from, struct array *to, int reference_strings)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
3f268a2006-03-09Henrik Grubbström (Grubba)  INT32 e, num;
a8cdf92004-04-29Martin Nilsson 
dc384d2006-03-11Henrik Grubbström (Grubba)  ctx->v = NULL; ctx->empty_repl = NULL;
7f0f342006-03-09Henrik Grubbström (Grubba) 
652b672008-05-01Martin Stjernholm #if INT32_MAX >= LONG_MAX
99e4f02004-10-15Henrik Grubbström (Grubba)  /* NOTE: The following test is needed, since sizeof(struct tupel) * is somewhat greater than sizeof(struct svalue). */
dc384d2006-03-11Henrik Grubbström (Grubba)  if (from->size > (ptrdiff_t)(LONG_MAX/sizeof(struct replace_many_tupel)))
99e4f02004-10-15Henrik Grubbström (Grubba)  Pike_error("Array too large (size %" PRINTPTRDIFFT "d "
bd5e8b2004-10-16Marcus Agehall  "exceeds %" PRINTSIZET "u).\n",
dc384d2006-03-11Henrik Grubbström (Grubba)  from->size, (size_t)(LONG_MAX/sizeof(struct replace_many_tupel)));
652b672008-05-01Martin Stjernholm #endif
dc384d2006-03-11Henrik Grubbström (Grubba)  ctx->v = (struct replace_many_tupel *) xalloc(sizeof(struct replace_many_tupel) * from->size);
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)  {
24e45c2006-03-11Henrik Grubbström (Grubba)  if (!ITEM(from)[e].u.string->len) { if (ITEM(to)[e].u.string->len) {
dc384d2006-03-11Henrik Grubbström (Grubba)  ctx->empty_repl = ITEM(to)[e].u.string;
24e45c2006-03-11Henrik Grubbström (Grubba)  } continue; }
dc384d2006-03-11Henrik Grubbström (Grubba)  ctx->v[num].ind=ITEM(from)[e].u.string; ctx->v[num].val=ITEM(to)[e].u.string; ctx->v[num].prefix=-2; /* Uninitialized */ ctx->v[num].is_prefix=0;
3e625c1998-10-11Fredrik Hübinette (Hubbe)  num++;
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
dc384d2006-03-11Henrik Grubbström (Grubba)  ctx->flags = reference_strings; if (reference_strings) { /* Used for the precompiled compiled case. */ if (ctx->empty_repl) add_ref(ctx->empty_repl); for (e = 0; e < num; e++) { add_ref(ctx->v[e].ind); add_ref(ctx->v[e].val); } }
5267b71995-08-09Fredrik Hübinette (Hubbe) 
dc384d2006-03-11Henrik Grubbström (Grubba)  fsort((char *)ctx->v, num, sizeof(struct replace_many_tupel), (fsortfun)replace_sortfun);
21b12a2014-09-03Martin Nilsson  memset(ctx->set_start, 0, sizeof(ctx->set_start)); memset(ctx->set_end, 0, sizeof(ctx->set_end));
dc384d2006-03-11Henrik Grubbström (Grubba)  ctx->other_start = num;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
3e625c1998-10-11Fredrik Hübinette (Hubbe)  for(e=0;e<num;e++)
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
24e45c2006-03-11Henrik Grubbström (Grubba)  { p_wchar2 x;
dc384d2006-03-11Henrik Grubbström (Grubba)  if (ctx->v[num-1-e].ind->len) { x=index_shared_string(ctx->v[num-1-e].ind,0);
7489bb2008-06-29Martin Stjernholm  if ((size_t) x < NELEM(ctx->set_start))
dc384d2006-03-11Henrik Grubbström (Grubba)  ctx->set_start[x]=num-e-1;
24e45c2006-03-11Henrik Grubbström (Grubba)  else
dc384d2006-03-11Henrik Grubbström (Grubba)  ctx->other_start = num-e-1;
24e45c2006-03-11Henrik Grubbström (Grubba)  }
dc384d2006-03-11Henrik Grubbström (Grubba)  if (ctx->v[e].ind->len) { x=index_shared_string(ctx->v[e].ind,0);
7489bb2008-06-29Martin Stjernholm  if ((size_t) x < NELEM(ctx->set_end))
dc384d2006-03-11Henrik Grubbström (Grubba)  ctx->set_end[x]=e+1;
24e45c2006-03-11Henrik Grubbström (Grubba)  } } { INT32 prefix = e-1; if (prefix >= 0) { ptrdiff_t tmp =
dc384d2006-03-11Henrik Grubbström (Grubba)  generic_find_binary_prefix(ctx->v[e].ind->str, ctx->v[e].ind->len, ctx->v[e].ind->size_shift, ctx->v[prefix].ind->str, ctx->v[prefix].ind->len, ctx->v[prefix].ind->size_shift);
24e45c2006-03-11Henrik Grubbström (Grubba)  if (!tmp) {
dc384d2006-03-11Henrik Grubbström (Grubba)  /* ctx->v[prefix] is a valid prefix to ctx->v[e]. */
24e45c2006-03-11Henrik Grubbström (Grubba)  } if (tmp == 1) { /* Optimization. */ prefix = -1; } else {
d8fc6f2006-03-10Henrik Grubbström (Grubba) #ifdef PIKE_DEBUG
24e45c2006-03-11Henrik Grubbström (Grubba)  if (tmp < 0) Pike_fatal("Sorting with replace_sortfunc failed.\n");
d8fc6f2006-03-10Henrik Grubbström (Grubba) #endif
18d9352006-03-10Henrik Grubbström (Grubba) 
24e45c2006-03-11Henrik Grubbström (Grubba)  /* Find the first prefix that is shorter than the point at which * the initial strings differed. */ while (prefix >= 0) {
dc384d2006-03-11Henrik Grubbström (Grubba)  if (ctx->v[prefix].ind->len < tmp) break; prefix = ctx->v[prefix].prefix;
24e45c2006-03-11Henrik Grubbström (Grubba)  } } if (prefix >= 0) {
dc384d2006-03-11Henrik Grubbström (Grubba)  ctx->v[prefix].is_prefix = 1;
d8fc6f2006-03-10Henrik Grubbström (Grubba)  }
3f268a2006-03-09Henrik Grubbström (Grubba)  }
dc384d2006-03-11Henrik Grubbström (Grubba)  ctx->v[e].prefix = prefix;
3f268a2006-03-09Henrik Grubbström (Grubba)  }
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
dc384d2006-03-11Henrik Grubbström (Grubba)  ctx->num = num; }
5267b71995-08-09Fredrik Hübinette (Hubbe) 
dc384d2006-03-11Henrik Grubbström (Grubba) struct pike_string *execute_replace_many(struct replace_many_context *ctx, struct pike_string *str) { struct string_builder ret; ONERROR uwp; init_string_builder(&ret, str->size_shift); SET_ONERROR(uwp, free_string_builder, &ret);
5267b71995-08-09Fredrik Hübinette (Hubbe) 
2a7ae62006-03-10Henrik Grubbström (Grubba)  /* FIXME: We really ought to build a trie! */
d8fc6f2006-03-10Henrik Grubbström (Grubba) 
007b462006-03-11Henrik Grubbström (Grubba)  switch (str->size_shift) { #define CASE(SZ) \ case (SZ): \ { \ PIKE_CONCAT(p_wchar, SZ) *ss = \ PIKE_CONCAT(STR, SZ)(str); \
dc384d2006-03-11Henrik Grubbström (Grubba)  ptrdiff_t e, s, length = str->len; \
007b462006-03-11Henrik Grubbström (Grubba)  for(e = s = 0;length > 0;) \ { \ INT32 a, b; \ p_wchar2 ch; \ \ ch = ss[s]; \ if(OPT_IS_CHAR(ch)) { \
dc384d2006-03-11Henrik Grubbström (Grubba)  b = ctx->set_end[ch]; \
007b462006-03-11Henrik Grubbström (Grubba)  if (!b) \ goto PIKE_CONCAT(next_char, SZ); \
dc384d2006-03-11Henrik Grubbström (Grubba)  a = ctx->set_start[ch]; \
007b462006-03-11Henrik Grubbström (Grubba)  } else { \
dc384d2006-03-11Henrik Grubbström (Grubba)  b = ctx->num; \ a = ctx->other_start; \
007b462006-03-11Henrik Grubbström (Grubba)  } \ if (a >= b) \ goto PIKE_CONCAT(next_char, SZ); \ \ a = find_longest_prefix((char *)(ss + s), \ length, \ SZ, \
dc384d2006-03-11Henrik Grubbström (Grubba)  ctx->v, a, b); \
007b462006-03-11Henrik Grubbström (Grubba)  \ if(a >= 0) \ { \ if (s != e) { \ PIKE_CONCAT(string_builder_binary_strcat, \
dc384d2006-03-11Henrik Grubbström (Grubba)  SZ)(&ret, ss+e, s-e); \
007b462006-03-11Henrik Grubbström (Grubba)  } \
dc384d2006-03-11Henrik Grubbström (Grubba)  ch = ctx->v[a].ind->len; \
007b462006-03-11Henrik Grubbström (Grubba)  s += ch; \ length -= ch; \ e = s; \
dc384d2006-03-11Henrik Grubbström (Grubba)  string_builder_shared_strcat(&ret, \ ctx->v[a].val); \ if (ctx->empty_repl && length) { \
007b462006-03-11Henrik Grubbström (Grubba)  /* Append the replacement for \ * the empty string too. */ \
dc384d2006-03-11Henrik Grubbström (Grubba)  string_builder_shared_strcat(&ret, \ ctx->empty_repl); \
007b462006-03-11Henrik Grubbström (Grubba)  } \ continue; \ } \ \ PIKE_CONCAT(next_char, SZ): \ s++; \ length--; \
dc384d2006-03-11Henrik Grubbström (Grubba)  if (ctx->empty_repl && length) { \
007b462006-03-11Henrik Grubbström (Grubba)  /* We have a replace with the empty string, \ * and we're not on the last character \ * in the source string. \ */ \
dc384d2006-03-11Henrik Grubbström (Grubba)  string_builder_putchar(&ret, ch); \ string_builder_shared_strcat(&ret, \ ctx->empty_repl); \
007b462006-03-11Henrik Grubbström (Grubba)  e = s; \ } \ } \ if (e < s) { \ PIKE_CONCAT(string_builder_binary_strcat, SZ) \
dc384d2006-03-11Henrik Grubbström (Grubba)  (&ret, ss+e, s-e); \
007b462006-03-11Henrik Grubbström (Grubba)  } \ } \ break #define OPT_IS_CHAR(X) 1 CASE(0); #undef OPT_IS_CHAR
7489bb2008-06-29Martin Stjernholm #define OPT_IS_CHAR(X) ((size_t) (X) < NELEM(ctx->set_end))
007b462006-03-11Henrik Grubbström (Grubba)  CASE(1); CASE(2); #undef OPT_IS_CHAR
d8fc6f2006-03-10Henrik Grubbström (Grubba)  }
5267b71995-08-09Fredrik Hübinette (Hubbe) 
dc384d2006-03-11Henrik Grubbström (Grubba)  UNSET_ONERROR(uwp); return finish_string_builder(&ret); } static struct pike_string *replace_many(struct pike_string *str, struct array *from, struct array *to) { struct replace_many_context ctx; ONERROR uwp; struct pike_string *ret; if(from->size != to->size) Pike_error("Replace must have equal-sized from and to arrays.\n"); if(!from->size) { reference_shared_string(str); return str; } if( (from->type_field & ~BIT_STRING) && (array_fix_type_field(from) & ~BIT_STRING) ) Pike_error("replace: from array not array(string).\n"); if( (to->type_field & ~BIT_STRING) && (array_fix_type_field(to) & ~BIT_STRING) ) Pike_error("replace: to array not array(string).\n"); if (from->size == 1) { /* Just a single string... */ return string_replace(str, from->item[0].u.string, to->item[0].u.string); } compile_replace_many(&ctx, from, to, 0); SET_ONERROR(uwp, free_replace_many_context, &ctx); ret = execute_replace_many(&ctx, str); CALL_AND_UNSET_ONERROR(uwp); return 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)
7f0f342006-03-09Henrik Grubbström (Grubba)  *! @decl string replace(string s, array(string) from, 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:
13670c2015-05-25Martin Nilsson  *!
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]
bf2c0d2018-01-12Stephen R. van den Berg  *! a mapping equivalent 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 &&
017b572011-10-28Henrik Grubbström (Grubba)  TYPEOF(Pike_sp[-1]) == 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) ) {
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("replace", 2, "mapping(string:string)");
200bfd2004-05-14Martin Nilsson  } }
f7a4462000-10-31Mirar (Pontus Hagland)  stack_dup(); f_indices(1); stack_swap(); f_values(1); args++; } else
06bd612016-01-26Martin Nilsson  SIMPLE_WRONG_NUM_ARGS_ERROR("replace", 3);
7f0f342006-03-09Henrik Grubbström (Grubba)  } else if (args > 3) { pop_n_elems(args-3); args = 3;
f7a4462000-10-31Mirar (Pontus Hagland)  }
5267b71995-08-09Fredrik Hübinette (Hubbe) 
017b572011-10-28Henrik Grubbström (Grubba)  switch(TYPEOF(Pike_sp[-args]))
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;
017b572011-10-28Henrik Grubbström (Grubba)  switch(TYPEOF(Pike_sp[1-args]))
5267b71995-08-09Fredrik Hübinette (Hubbe)  { default:
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("replace", 2, "string|array");
a8cdf92004-04-29Martin Nilsson 
5267b71995-08-09Fredrik Hübinette (Hubbe)  case T_STRING:
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[2-args]) != T_STRING)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_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;
13670c2015-05-25Martin Nilsson 
5267b71995-08-09Fredrik Hübinette (Hubbe)  case T_ARRAY:
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[2-args]) == T_STRING) {
7f0f342006-03-09Henrik Grubbström (Grubba)  push_int(Pike_sp[1-args].u.array->size); stack_swap(); f_allocate(2);
017b572011-10-28Henrik Grubbström (Grubba)  } else if(TYPEOF(Pike_sp[2-args]) != T_ARRAY)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("replace", 3, "array|string");
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);
13670c2015-05-25Martin Nilsson 
5267b71995-08-09Fredrik Hübinette (Hubbe)  } pop_n_elems(args); push_string(s); break; }
8b63781996-04-11Fredrik Hübinette (Hubbe)  default:
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_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;
5527f72008-01-13Henrik Grubbström (Grubba)  if (!arg0) return NULL;
6377672001-06-01Henrik Grubbström (Grubba)  MAKE_CONSTANT_TYPE(array_zero, tArr(tZero)); MAKE_CONSTANT_TYPE(mapping_zero, tMap(tZero, tZero));
5527f72008-01-13Henrik Grubbström (Grubba)  if ((pike_types_le(array_zero, (*arg0)->type) ||
6377672001-06-01Henrik Grubbström (Grubba)  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, *
229f692004-12-18Henrik Grubbström (Grubba)  * It must thus be a string.
fed7de2001-06-28Henrik Grubbström (Grubba)  */ node **arg1 = my_get_arg(&_CDR(n), 1); node **arg2 = my_get_arg(&_CDR(n), 2);
52af792014-10-22Arne Goedeke  /* This variable is modified in between setjmp and longjmp, * so it needs to be volatile to prevent it from being globbered. */ struct program * volatile replace_compiler = NULL;
fed7de2001-06-28Henrik Grubbström (Grubba) 
dc384d2006-03-11Henrik Grubbström (Grubba)  if (arg1 && ((pike_types_le((*arg1)->type, array_type_string) && arg2 && (pike_types_le((*arg2)->type, array_type_string) || pike_types_le((*arg2)->type, string_type_string))) || (pike_types_le((*arg1)->type, mapping_type_string)))) { /* Handle the cases: * * replace(string, array, array) * replace(string, array, string) * replace(string, mapping(string:string)) */
a842b22006-03-11Henrik Grubbström (Grubba)  extern struct program *multi_string_replace_program; replace_compiler = multi_string_replace_program; } else if (arg1 && pike_types_le((*arg1)->type, string_type_string) && arg2 && pike_types_le((*arg2)->type, string_type_string)) { extern struct program *single_string_replace_program; replace_compiler = single_string_replace_program; } if (replace_compiler && !is_const(*arg0) && is_const(*arg1) && (!arg2 || is_const(*arg2))) { /* The second and third (if any) arguments are constants. */ struct svalue *save_sp = Pike_sp; JMP_BUF tmp; if (SETJMP(tmp)) {
1ab4ac2008-01-26Martin Stjernholm  struct svalue thrown;
a842b22006-03-11Henrik Grubbström (Grubba)  struct pike_string *s;
1ab4ac2008-01-26Martin Stjernholm  move_svalue (&thrown, &throw_value); mark_free_svalue (&throw_value);
a842b22006-03-11Henrik Grubbström (Grubba)  pop_n_elems(Pike_sp - save_sp); yywarning("Optimizer failure in replace()."); s = format_exception_for_error_msg (&thrown); if (s) { yywarning ("%S", s); free_string (s); } free_svalue(&thrown); } else { INT16 lfun; struct object *replace_obj; node *ret = NULL; INT32 args; args = eval_low(*arg1, 1);
2e45e22008-01-23Henrik Grubbström (Grubba)  if (args != 1) goto failed;
a842b22006-03-11Henrik Grubbström (Grubba)  if (arg2) {
1759c42008-01-21Henrik Grubbström (Grubba)  args += eval_low(*arg2, 1); if (!args) { /* eval_low() returned -1. */
2e45e22008-01-23Henrik Grubbström (Grubba)  goto failed;
1759c42008-01-21Henrik Grubbström (Grubba)  }
a842b22006-03-11Henrik Grubbström (Grubba)  }
cbd1f22001-06-29Henrik Grubbström (Grubba) 
a842b22006-03-11Henrik Grubbström (Grubba)  replace_obj = clone_object(replace_compiler, args);
fed7de2001-06-28Henrik Grubbström (Grubba) 
a842b22006-03-11Henrik Grubbström (Grubba)  push_object(replace_obj); if (replace_obj->prog && ((lfun = FIND_LFUN(replace_obj->prog, LFUN_CALL)) != -1)) {
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(Pike_sp[-1], PIKE_T_FUNCTION, lfun, object, replace_obj);
a842b22006-03-11Henrik Grubbström (Grubba)  ADD_NODE_REF2(*arg0, ret = mkapplynode(mkconstantsvaluenode(Pike_sp-1), *arg0); );
fed7de2001-06-28Henrik Grubbström (Grubba) 
a842b22006-03-11Henrik Grubbström (Grubba)  UNSETJMP(tmp); pop_n_elems(Pike_sp - save_sp);
fed7de2001-06-28Henrik Grubbström (Grubba) 
a842b22006-03-11Henrik Grubbström (Grubba)  free_type(array_zero); free_type(mapping_zero); return ret;
fed7de2001-06-28Henrik Grubbström (Grubba)  } }
2e45e22008-01-23Henrik Grubbström (Grubba)  failed:
a842b22006-03-11Henrik Grubbström (Grubba)  UNSETJMP(tmp); 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; }
e290f32006-01-27Henrik Grubbström (Grubba) /*! @decl program compile(string source, CompilationHandler|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
e290f32006-01-27Henrik Grubbström (Grubba)  *! @[compile_string()], @[compile_file()], @[cpp()], @[master()],
71d3902008-06-01Henrik Grubbström (Grubba)  *! @[CompilationHandler], @[DefaultCompilerEnvironment]
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) {
41c9152008-04-18Henrik Grubbström (Grubba)  apply_low(compilation_environment, CE_COMPILE_FUN_NUM, args);
5267b71995-08-09Fredrik Hübinette (Hubbe) }
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:
13670c2015-05-25Martin Nilsson  *!
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
13670c2015-05-25Martin Nilsson  *!
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;
017b572011-10-28Henrik Grubbström (Grubba)  switch(TYPEOF(*s))
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:
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_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) {
06bd612016-01-26Martin Nilsson  if(args!=1) SIMPLE_WRONG_NUM_ARGS_ERROR("objectp", 1);
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[-args]) != T_OBJECT || !Pike_sp[-args].u.object->prog
0311712013-06-17Martin Nilsson  || is_bignum_object(Pike_sp[-args].u.object))
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;
06bd612016-01-26Martin Nilsson  if(args!=1) SIMPLE_WRONG_NUM_ARGS_ERROR("functionp", 1);
017b572011-10-28Henrik Grubbström (Grubba)  if( TYPEOF(Pike_sp[-args]) == T_FUNCTION && (SUBTYPEOF(Pike_sp[-args]) == FUNCTION_BUILTIN || Pike_sp[-args].u.object->prog))
2e04432001-04-09Per Hedbor  res=1; pop_n_elems(args); push_int(res); }
47bb042015-12-12Henrik Grubbström (Grubba) PMOD_EXPORT int callablep(struct svalue *s)
2e04432001-04-09Per Hedbor {
d476332013-12-14Martin Nilsson  switch( TYPEOF(*s) )
5267b71995-08-09Fredrik Hübinette (Hubbe)  {
2e04432001-04-09Per Hedbor  case T_FUNCTION:
b8619b2013-12-14Henrik Grubbström (Grubba)  if( SUBTYPEOF(*s) == FUNCTION_BUILTIN || s->u.object->prog)
4799242015-12-14Martin Nilsson  return 1;
2e04432001-04-09Per Hedbor  break; case T_PROGRAM:
4799242015-12-14Martin Nilsson  return 1;
2e04432001-04-09Per Hedbor  break; case T_OBJECT:
f54c782004-12-22Henrik Grubbström (Grubba)  { struct program *p;
d476332013-12-14Martin Nilsson  if((p = s->u.object->prog) && FIND_LFUN(p->inherits[SUBTYPEOF(*s)].prog,
f54c782004-12-22Henrik Grubbström (Grubba)  LFUN_CALL ) != -1)
4799242015-12-14Martin Nilsson  return 1;
f54c782004-12-22Henrik Grubbström (Grubba)  }
e8a76d2003-10-30Martin Nilsson  break; case T_ARRAY:
4799242015-12-14Martin Nilsson  { int ret = 0; DECLARE_CYCLIC(); if (BEGIN_CYCLIC(s, NULL)) { END_CYCLIC(); return 1; } SET_CYCLIC_RET((ptrdiff_t)1);
d476332013-12-14Martin Nilsson  array_fix_type_field(s->u.array); if( !s->u.array->type_field) {
b8619b2013-12-14Henrik Grubbström (Grubba)  ret = 1;
a8cdf92004-04-29Martin Nilsson  }
4799242015-12-14Martin Nilsson  else if( !(s->u.array->type_field & ~(BIT_CALLABLE|BIT_INT)) ) {
d476332013-12-14Martin Nilsson  struct array *a = s->u.array;
a8cdf92004-04-29Martin Nilsson  int i;
b8619b2013-12-14Henrik Grubbström (Grubba)  ret = 1;
a8cdf92004-04-29Martin Nilsson  for(i=0; i<a->size; i++)
4799242015-12-14Martin Nilsson  if( TYPEOF(ITEM(a)[i])!=T_INT && !callablep(&ITEM(a)[i]) ) { ret = 0; break; }
a8cdf92004-04-29Martin Nilsson  }
4799242015-12-14Martin Nilsson  END_CYCLIC(); return ret;
e8a76d2003-10-30Martin Nilsson  break;
4799242015-12-14Martin Nilsson  }
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
b8619b2013-12-14Henrik Grubbström (Grubba) 
4799242015-12-14Martin Nilsson  return 0;
d476332013-12-14Martin Nilsson } /*! @decl int callablep(mixed arg) *! *! Returns @expr{1@} if @[arg] is a callable, @expr{0@} (zero) otherwise. *! *! @seealso *! @[mappingp()], @[programp()], @[arrayp()], @[stringp()], @[objectp()], *! @[multisetp()], @[floatp()], @[intp()] */ PMOD_EXPORT void f_callablep(INT32 args) { int res = 0;
06bd612016-01-26Martin Nilsson  if(args!=1) SIMPLE_WRONG_NUM_ARGS_ERROR("callablep", 1);
d476332013-12-14Martin Nilsson  res = callablep(&Pike_sp[-args]);
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
3714062010-02-18Stephen R. van den Berg static void delaysleep(double delay, unsigned do_abort_on_signal, unsigned do_microsleep)
cb22561995-10-11Fredrik Hübinette (Hubbe) {
3714062010-02-18Stephen R. van den Berg #define POLL_SLEEP_LIMIT 0.02
aba79f2011-11-17Tobias S. Josefowitz  struct timeval gtod_t0 = {0,0}, gtod_tv = {0,0};
e611d32011-03-31Martin Stjernholm  cpu_time_t t0, tv;
bebcca2001-11-08Fredrik Hübinette (Hubbe) 
3714062010-02-18Stephen R. van den Berg  /* Special case, sleep(0) means 'yield' */ if(delay == 0.0) { check_threads_etc();
5d63712010-09-28Martin Stjernholm  /* Since check_threads doesn't yield on every call, we need this * to ensure th_yield gets called. */ pike_thread_yield();
3714062010-02-18Stephen R. van den Berg  return; } if(sizeof(FLOAT_TYPE)<sizeof(double)) delay += FLT_EPSILON*5; /* round up */
bebcca2001-11-08Fredrik Hübinette (Hubbe) 
e611d32011-03-31Martin Stjernholm  t0 = tv = get_real_time(); if (t0 == -1) { /* Paranoia in case get_real_time fails. */ /* fprintf (stderr, "get_real_time failed in sleep()\n"); */
f010202011-11-16Tobias S. Josefowitz  ACCURATE_GETTIMEOFDAY (&gtod_t0);
e611d32011-03-31Martin Stjernholm  gtod_tv = gtod_t0; }
bebcca2001-11-08Fredrik Hübinette (Hubbe) 
e611d32011-03-31Martin Stjernholm #define FIX_LEFT() \ if (t0 == -1) { \
f010202011-11-16Tobias S. Josefowitz  ACCURATE_GETTIMEOFDAY (&gtod_tv); \
e611d32011-03-31Martin Stjernholm  left = delay - ((gtod_tv.tv_sec-gtod_t0.tv_sec) + \ (gtod_tv.tv_usec-gtod_t0.tv_usec)*1e-6); \ } \ else { \ tv = get_real_time(); \ left = delay - (tv - t0) * (1.0 / CPU_TIME_TICKS); \ } \ if (do_microsleep) left-=POLL_SLEEP_LIMIT;
3714062010-02-18Stephen R. van den Berg  if (!do_microsleep || delay>POLL_SLEEP_LIMIT) { for(;;) { double left; /* THREADS_ALLOW may take longer time then POLL_SLEEP_LIMIT */ THREADS_ALLOW(); FIX_LEFT(); if(left>0.0) sysleep(left); THREADS_DISALLOW();
5f74502011-01-24Martin Stjernholm  if(do_abort_on_signal) {
f010202011-11-16Tobias S. Josefowitz  INVALIDATE_CURRENT_TIME();
3714062010-02-18Stephen R. van den Berg  return;
5f74502011-01-24Martin Stjernholm  }
3714062010-02-18Stephen R. van den Berg  FIX_LEFT(); if(left<=0.0) break; check_threads_etc(); }
f010202011-11-16Tobias S. Josefowitz  INVALIDATE_CURRENT_TIME();
3714062010-02-18Stephen R. van den Berg  }
e611d32011-03-31Martin Stjernholm  if (do_microsleep) { if (t0 == -1) { while (delay> ((gtod_tv.tv_sec-gtod_t0.tv_sec) + (gtod_tv.tv_usec-gtod_t0.tv_usec)*1e-6))
f010202011-11-16Tobias S. Josefowitz  ACCURATE_GETTIMEOFDAY (&gtod_tv);
e611d32011-03-31Martin Stjernholm  } else { while (delay> (tv - t0) * (1.0 / CPU_TIME_TICKS)) tv = get_real_time(); } } /* fprintf (stderr, "slept %g\n", (tv - t0) * (1.0 / CPU_TIME_TICKS)); */
3714062010-02-18Stephen R. van den Berg } /*! @decl void sleep(int|float s, void|int abort_on_signal) *!
38ee6f2017-05-24Henrik Grubbström (Grubba)  *! This function makes the thread stop for @[s] seconds.
3714062010-02-18Stephen R. van den Berg  *! *! 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. *! *! 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. *! *! @seealso *! @[signal()], @[delay()] */ PMOD_EXPORT void f_sleep(INT32 args) { double delay=0.0; unsigned do_abort_on_signal;
bebcca2001-11-08Fredrik Hübinette (Hubbe) 
017b572011-10-28Henrik Grubbström (Grubba)  switch(TYPEOF(Pike_sp[-args]))
bebcca2001-11-08Fredrik Hübinette (Hubbe)  { case T_INT: delay=(double)Pike_sp[-args].u.integer; break; case T_FLOAT: delay=(double)Pike_sp[-args].u.float_number; break; }
3714062010-02-18Stephen R. van den Berg  do_abort_on_signal = delay!=0.0 && args > 1 && !UNSAFE_IS_ZERO(Pike_sp + 1-args);
bebcca2001-11-08Fredrik Hübinette (Hubbe)  pop_n_elems(args);
3714062010-02-18Stephen R. van den Berg  delaysleep(delay, do_abort_on_signal, 0);
bebcca2001-11-08Fredrik Hübinette (Hubbe) } #undef FIX_LEFT #undef TIME_ELAPSED /*! @decl void delay(int|float s) *!
38ee6f2017-05-24Henrik Grubbström (Grubba)  *! This function makes the thread stop for @[s] seconds.
bebcca2001-11-08Fredrik Hübinette (Hubbe)  *! *! 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.
13670c2015-05-25Martin Nilsson  *!
bebcca2001-11-08Fredrik Hübinette (Hubbe)  *! @seealso *! @[signal()], @[sleep()] */ PMOD_EXPORT void f_delay(INT32 args) {
8380171999-12-06Mirar (Pontus Hagland)  double delay=0.0;
3714062010-02-18Stephen R. van den Berg  unsigned do_abort_on_signal;
0dbb5c2000-02-22Fredrik Hübinette (Hubbe) 
017b572011-10-28Henrik Grubbström (Grubba)  switch(TYPEOF(Pike_sp[-args]))
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) 
3714062010-02-18Stephen R. van den Berg  do_abort_on_signal = delay!=0.0 && args > 1 && !UNSAFE_IS_ZERO(Pike_sp + 1-args);
8380171999-12-06Mirar (Pontus Hagland)  pop_n_elems(args);
3714062010-02-18Stephen R. van den Berg  delaysleep(delay, do_abort_on_signal, !do_abort_on_signal && delay<10);
cb22561995-10-11Fredrik Hübinette (Hubbe) }
ccc34a2016-03-01Henrik Grubbström (Grubba) /*! @decl int gc(mapping|array|void quick)
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
554e222001-05-06Henrik Grubbström (Grubba)  *! Force garbage collection.
ed1cc32001-01-09Henrik Grubbström (Grubba)  *!
2868742016-02-29Henrik Grubbström (Grubba)  *! @param quick *! Perform a quick garbage collection on just this value, *! which must have been made weak by @[set_weak_flag()]. *! All values that only have a single reference from
b110332016-02-29Henrik Grubbström (Grubba)  *! @[quick] will then be freed.
2868742016-02-29Henrik Grubbström (Grubba)  *! *! When @[quick] hasn't been specified or is @[UNDEFINED], *! this function checks all the memory for cyclic structures such
554e222001-05-06Henrik Grubbström (Grubba)  *! 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
f76ace2017-11-05Henrik Grubbström (Grubba)  *! difference since _destruct() functions are called during freeing,
5a0d5b2003-01-11Martin Stjernholm  *! 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) {
2868742016-02-29Henrik Grubbström (Grubba)  ptrdiff_t res = 0;
ccc34a2016-03-01Henrik Grubbström (Grubba)  switch(args? TYPEOF(Pike_sp[-args]): PIKE_T_MIXED) { case PIKE_T_MAPPING:
2868742016-02-29Henrik Grubbström (Grubba)  res = do_gc_weak_mapping(Pike_sp[-args].u.mapping); pop_n_elems(args);
ccc34a2016-03-01Henrik Grubbström (Grubba)  break; case PIKE_T_ARRAY: res = do_gc_weak_array(Pike_sp[-args].u.array); pop_n_elems(args); break; default:
2868742016-02-29Henrik Grubbström (Grubba)  pop_n_elems(args); res = do_gc(NULL, 1);
ccc34a2016-03-01Henrik Grubbström (Grubba)  break;
2868742016-02-29Henrik Grubbström (Grubba)  } push_int(res);
624d091996-02-24Fredrik Hübinette (Hubbe) }
5267b71995-08-09Fredrik Hübinette (Hubbe) #ifdef TYPEP #undef TYPEP #endif
aa73fc1999-10-21Fredrik Hübinette (Hubbe) 
f54c782004-12-22Henrik Grubbström (Grubba) #define TYPEP(ID,NAME,TYPE,TYPE_NAME) \ PMOD_EXPORT void ID(INT32 args) \ { \ int t; \ struct program *p; \
06bd612016-01-26Martin Nilsson  if (args!=1) \ SIMPLE_WRONG_NUM_ARGS_ERROR(NAME, 1); \
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-args]) == T_OBJECT && \
f54c782004-12-22Henrik Grubbström (Grubba)  (p = Pike_sp[-args].u.object->prog)) \ { \
017b572011-10-28Henrik Grubbström (Grubba)  int fun = FIND_LFUN(p->inherits[SUBTYPEOF(Pike_sp[-args])].prog, \
f54c782004-12-22Henrik Grubbström (Grubba)  LFUN__IS_TYPE); \ if (fun != -1) \ { \ int id_level = \
017b572011-10-28Henrik Grubbström (Grubba)  p->inherits[SUBTYPEOF(Pike_sp[-args])].identifier_level; \
6a932b2014-08-18Martin Nilsson  ref_push_string(literal_##TYPE_NAME##_string); \
f54c782004-12-22Henrik Grubbström (Grubba)  apply_low(Pike_sp[-args-1].u.object, fun + id_level, 1); \ stack_unlink(args); \ return; \ } \ } \
017b572011-10-28Henrik Grubbström (Grubba)  t = TYPEOF(Pike_sp[-args]) == TYPE; \
f54c782004-12-22Henrik Grubbström (Grubba)  pop_n_elems(args); \ push_int(t); \ }
b1f4eb1998-01-13Fredrik Hübinette (Hubbe) 
e009522007-11-18Martin Nilsson /*! @decl int undefinedp(mixed arg) *! *! Returns @expr{1@} if @[arg] is undefined, @expr{0@} (zero) otherwise. *! *! @seealso *! @[zero_type], @[destructedp], @[intp] */ PMOD_EXPORT void f_undefinedp(INT32 args) {
06bd612016-01-26Martin Nilsson  if( args!=1 ) SIMPLE_WRONG_NUM_ARGS_ERROR("undefinedp", 1);
e009522007-11-18Martin Nilsson  f_zero_type(args); Pike_sp[-1].u.integer = ( Pike_sp[-1].u.integer == NUMBER_UNDEFINED); } /*! @decl int destructedp(mixed arg) *! *! Returns @expr{1@} if @[arg] is a destructed object, @expr{0@} *! (zero) otherwise. *! *! @seealso *! @[zero_type], @[undefinedp], @[intp] */ PMOD_EXPORT void f_destructedp(INT32 args) {
06bd612016-01-26Martin Nilsson  if( args!=1 ) SIMPLE_WRONG_NUM_ARGS_ERROR("destructedp", 1);
e009522007-11-18Martin Nilsson  f_zero_type(args); Pike_sp[-1].u.integer = ( Pike_sp[-1].u.integer == NUMBER_DESTRUCTED); }
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) {
06bd612016-01-26Martin Nilsson  if(args!=1) SIMPLE_WRONG_NUM_ARGS_ERROR("programp", 1);
017b572011-10-28Henrik Grubbström (Grubba)  switch(TYPEOF(Pike_sp[-args]))
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; }
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
b1f4eb1998-01-13Fredrik Hübinette (Hubbe)  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) 
6a932b2014-08-18Martin Nilsson 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.
13670c2015-05-25Martin Nilsson  *!
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)
06bd612016-01-26Martin Nilsson  SIMPLE_WRONG_NUM_ARGS_ERROR("sort", 1);
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[-args]) != T_ARRAY)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("sort", 1, "array");
0c49782003-04-27Martin Stjernholm  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)  {
017b572011-10-28Henrik Grubbström (Grubba)  if(TYPEOF(Pike_sp[e-args]) != T_ARRAY)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_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)
212c392018-02-25Martin Nilsson  bad_arg_error("sort", 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);