|
|
|
|
|
|
#include "global.h" |
#include "interpret.h" |
#include "svalue.h" |
#include "pike_macros.h" |
#include "object.h" |
#include "program.h" |
#include "array.h" |
#include "pike_error.h" |
#include "constants.h" |
#include "mapping.h" |
#include "stralloc.h" |
#include "multiset.h" |
#include "pike_types.h" |
#include "pike_rusage.h" |
#include "operators.h" |
#include "fsort.h" |
#include "callback.h" |
#include "gc.h" |
#include "backend.h" |
#include "main.h" |
#include "pike_memory.h" |
#include "threads.h" |
#include "time_stuff.h" |
#include "version.h" |
#include "encode.h" |
#include <math.h> |
#include <ctype.h> |
#include "module_support.h" |
#include "module.h" |
#include "opcodes.h" |
#include "cyclic.h" |
#include "signal_handler.h" |
#include "pike_security.h" |
#include "builtin_functions.h" |
#include "bignum.h" |
#include "peep.h" |
#include "docode.h" |
#include "lex.h" |
#include "pike_float.h" |
#include "pike_compiler.h" |
|
#include <errno.h> |
|
#ifdef HAVE_POLL |
#ifdef HAVE_POLL_H |
#include <poll.h> |
#endif /* HAVE_POLL_H */ |
|
#ifdef HAVE_SYS_POLL_H |
#include <sys/poll.h> |
#endif /* HAVE_SYS_POLL_H */ |
#endif /* HAVE_POLL */ |
|
#ifdef HAVE_CRYPT_H |
#include <crypt.h> |
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_equal(INT32 args) |
{ |
int i; |
if(args != 2) |
SIMPLE_TOO_FEW_ARGS_ERROR("equal", 2); |
|
i=is_equal(Pike_sp-2,Pike_sp-1); |
pop_n_elems(args); |
push_int(i); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void debug_f_aggregate(INT32 args) |
{ |
struct array *a; |
a=aggregate_array(args); |
push_array(a); |
} |
|
static node *optimize_f_aggregate(node *n) |
{ |
|
|
|
|
|
|
|
|
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) { |
|
count += 16; |
} else { |
count++; |
} |
if (!CAR(args)) break; |
CAR(args)->parent = args; |
} |
if (args->token == F_PUSH_ARRAY) { |
|
count += 16; |
} else if (args->token != F_ARG_LIST) { |
count++; |
} |
|
|
if (count <= 32) { |
CDR(n)->parent = n; |
return NULL; |
} |
|
|
|
|
|
|
|
count = 0; |
if (args->token != F_ARG_LIST) { |
if (args->token == F_PUSH_ARRAY) { |
|
add_args = copy_node(CAR(args)); |
} else { |
new_args = copy_node(args); |
count = 1; |
} |
args = args->parent; |
} |
|
for(; args; args = args->parent) { |
if (!CDR(args)) continue; |
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); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define MK_HASHMEM(NAME, TYPE) ATTRIBUTE((const)) \ |
static INLINE size_t NAME(const TYPE *str, ptrdiff_t len, ptrdiff_t maxn) \ |
{ \ |
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) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void f_hash_7_4(INT32 args) |
{ |
size_t i = 0; |
struct pike_string *s = Pike_sp[-args].u.string; |
|
if(!args) |
SIMPLE_TOO_FEW_ARGS_ERROR("7.4::hash",1); |
|
if(TYPEOF(Pike_sp[-args]) != T_STRING) |
SIMPLE_BAD_ARG_ERROR("7.4::hash", 1, "string"); |
|
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) |
SIMPLE_BAD_ARG_ERROR("7.4::hash",2,"int"); |
|
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); |
} |
|
|
|
|
|
|
|
ATTRIBUTE((const)) static INLINE size_t hashstr(const unsigned char *str, ptrdiff_t maxn) |
{ |
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; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void f_hash_7_0( INT32 args ) |
{ |
struct pike_string *s = Pike_sp[-args].u.string; |
unsigned int i; |
if(!args) |
SIMPLE_TOO_FEW_ARGS_ERROR("7.0::hash",1); |
if(TYPEOF(Pike_sp[-args]) != T_STRING) |
SIMPLE_BAD_ARG_ERROR("7.0::hash", 1, "string"); |
|
if( s->size_shift ) |
{ |
f_hash_7_4( args ); |
return; |
} |
|
i = DO_NOT_WARN((unsigned int)hashstr( (unsigned char *)s->str, |
MINIMUM(100,s->len))); |
if(args > 1) |
{ |
if(TYPEOF(Pike_sp[1-args]) != T_INT) |
SIMPLE_BAD_ARG_ERROR("7.0::hash",2,"int"); |
|
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 ); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_hash(INT32 args) |
{ |
size_t i = 0; |
struct pike_string *s; |
|
if(!args) |
SIMPLE_TOO_FEW_ARGS_ERROR("hash",1); |
|
if(TYPEOF(Pike_sp[-args]) != T_STRING) |
SIMPLE_BAD_ARG_ERROR("hash", 1, "string"); |
|
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; |
#ifdef PIKE_DEBUG |
default: |
Pike_fatal("hash(): Unsupported string shift: %d\n", s->size_shift); |
break; |
#endif |
} |
|
if(args > 1) |
{ |
if(TYPEOF(Pike_sp[1-args]) != T_INT) |
SIMPLE_BAD_ARG_ERROR("hash",2,"int"); |
|
if(Pike_sp[1-args].u.integer <= 0) |
PIKE_ERROR("hash", "Modulo < 1.\n", Pike_sp, args); |
|
i%=(unsigned INT32)Pike_sp[1-args].u.integer; |
} |
pop_n_elems(args); |
push_int64(i); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void f_hash_value(INT32 args) |
{ |
unsigned INT32 h; |
|
if(!args) |
SIMPLE_TOO_FEW_ARGS_ERROR("hash_value",1); |
|
h = hash_svalue (Pike_sp - args); |
pop_n_elems (args); |
push_int (h); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_copy_value(INT32 args) |
{ |
if(!args) |
SIMPLE_TOO_FEW_ARGS_ERROR("copy_value",1); |
|
pop_n_elems(args-1); |
push_undefined(); |
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--; |
dmalloc_touch_svalue(Pike_sp-1); |
} |
|
struct case_info { |
INT32 low; |
INT16 mode; |
INT16 data; |
}; |
|
#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. */ |
|
static const struct case_info case_info[] = { |
#include "case_info.h" |
{ 0x7fffffff, CIM_NONE, 0x0000, }, |
}; |
|
static struct case_info *find_ci(INT32 c) |
{ |
static struct case_info *cache = NULL; |
struct case_info *ci = cache; |
int lo = 0; |
int hi = NELEM(case_info); |
|
if ((c < 0) || (c > 0xeffff)) { |
|
return NULL; |
} |
|
if ((ci) && (ci[0].low <= c) && (ci[1].low > c)) { |
return ci; |
} |
|
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; |
} |
} |
return(cache = (struct case_info *)case_info + lo); |
} |
|
static struct case_info *find_ci_shift0(INT32 c) |
{ |
static struct case_info *cache = NULL; |
struct case_info *ci = cache; |
int lo = 0; |
int hi = CASE_INFO_SHIFT0_HIGH; |
|
if ((c < 0) || (c > 0xefffff)) { |
|
return NULL; |
} |
|
if ((ci) && (ci[0].low <= c) && (ci[1].low > c)) { |
return ci; |
} |
|
while (lo != hi-1) { |
int mid = (lo + hi)>>1; |
if (case_info[mid].low < c) { |
lo = mid; |
} else if (case_info[mid].low == c) { |
lo = mid; |
break; |
} else { |
hi = mid; |
} |
} |
return(cache = (struct case_info *)case_info + lo); |
} |
|
#define DO_LOWER_CASE(C) do {\ |
INT32 c = C; \ |
if(c<0xb5){if(c >= 'A' && c <= 'Z' ) C=c+0x20; } \ |
/*else if(c==0xa77d) C=0x1d79;*/ else { \ |
struct case_info *ci = find_ci(c); \ |
if (ci) { \ |
switch(ci->mode) { \ |
case CIM_NONE: case CIM_LOWERDELTA: case CIM_LONGLOWERDELTA: 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; \ |
case CIM_LONGUPPERDELTA: \ |
C = c + ci->data + ( ci->data>0 ? 0x7fff : -0x8000 ); break; \ |
DO_IF_DEBUG( default: Pike_fatal("lower_case(): Unknown case_info mode: %d\n", ci->mode); ) \ |
} \ |
}} \ |
} while(0) |
|
#define DO_LOWER_CASE_SHIFT0(C) do {\ |
INT32 c = C; \ |
if(c<0xb5){if(c >= 'A' && c <= 'Z' ) C=c+0x20;}else {\ |
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; \ |
DO_IF_DEBUG( default: Pike_fatal("lower_case(): Unknown case_info mode: %d\n", ci->mode); ) \ |
} \ |
}} \ |
} while(0) |
|
#define DO_UPPER_CASE(C) do {\ |
INT32 c = C; \ |
if(c<0xb5){if(c >= 'a' && c <= 'z' ) C=c-0x20; } \ |
/*else if(c==0x1d79) C=0xa77d;*/ else {\ |
struct case_info *ci = find_ci(c); \ |
if (ci) { \ |
switch(ci->mode) { \ |
case CIM_NONE: case CIM_UPPERDELTA: case CIM_LONGUPPERDELTA: 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; \ |
case CIM_LONGLOWERDELTA: \ |
C = c - ci->data - ( ci->data>0 ? 0x7fff : -0x8000 ); break; \ |
DO_IF_DEBUG( default: Pike_fatal("upper_case(): Unknown case_info mode: %d\n", ci->mode); ) \ |
} \ |
}} \ |
} while(0) |
|
#define DO_UPPER_CASE_SHIFT0(C) do {\ |
INT32 c = C; \ |
if(c<0xb5){if(c >= 'a' && c <= 'z' ) C=c-0x20;}else {\ |
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; \ |
DO_IF_DEBUG( default: Pike_fatal("lower_case(): Unknown case_info mode: %d\n", ci->mode); ) \ |
} \ |
}} \ |
} while(0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_lower_case(INT32 args) |
{ |
ptrdiff_t i; |
struct pike_string *orig; |
struct pike_string *ret; |
|
check_all_args("lower_case", args, BIT_STRING|BIT_INT, 0); |
|
if (TYPEOF(Pike_sp[-args]) == T_INT) { |
|
DO_LOWER_CASE(Pike_sp[-args].u.integer); |
pop_n_elems(args-1); |
return; |
} |
|
orig = Pike_sp[-args].u.string; |
|
if( orig->flags & STRING_IS_LOWERCASE ) |
return; |
|
ret = begin_wide_shared_string(orig->len, orig->size_shift); |
|
MEMCPY(ret->str, orig->str, orig->len << orig->size_shift); |
|
i = orig->len; |
|
if (!orig->size_shift) { |
p_wchar0 *str = STR0(ret); |
|
while(i--) { |
DO_LOWER_CASE_SHIFT0(str[i]); |
} |
} 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]); |
} |
#ifdef PIKE_DEBUG |
} else { |
Pike_fatal("lower_case(): Bad string shift:%d\n", orig->size_shift); |
#endif |
} |
|
ret = end_shared_string(ret); |
ret->flags |= STRING_IS_LOWERCASE; |
pop_n_elems(args); |
push_string(ret); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_upper_case(INT32 args) |
{ |
ptrdiff_t i; |
struct pike_string *orig; |
struct pike_string *ret; |
check_all_args("upper_case", args, BIT_STRING|BIT_INT, 0); |
|
if (TYPEOF(Pike_sp[-args]) == T_INT) { |
|
DO_UPPER_CASE(Pike_sp[-args].u.integer); |
pop_n_elems(args-1); |
return; |
} |
|
orig = Pike_sp[-args].u.string; |
if( orig->flags & STRING_IS_UPPERCASE ) |
{ |
return; |
} |
|
ret=begin_wide_shared_string(orig->len,orig->size_shift); |
MEMCPY(ret->str, orig->str, orig->len << orig->size_shift); |
|
i = orig->len; |
|
if (!orig->size_shift) { |
p_wchar0 *str = STR0(ret); |
|
while(i--) { |
if(str[i]!=0xff && str[i]!=0xb5) { |
DO_UPPER_CASE_SHIFT0(str[i]); |
} else { |
|
|
|
int j = orig->len; |
struct pike_string *wret = begin_wide_shared_string(j, 1); |
p_wchar1 *wstr = STR1(wret); |
|
|
while(--j>i) |
wstr[j] = str[j]; |
|
|
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; |
} |
|
|
do_free_unlinked_pike_string(ret); |
ret = wret; |
break; |
} |
} |
} 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]); |
} |
#ifdef PIKE_DEBUG |
} else { |
Pike_fatal("lower_case(): Bad string shift:%d\n", orig->size_shift); |
#endif |
} |
|
pop_n_elems(args); |
ret = end_shared_string(ret); |
ret->flags |= STRING_IS_UPPERCASE; |
push_string(ret); |
} |
|
|
|
|
|
PMOD_EXPORT void f_random_string(INT32 args) |
{ |
struct pike_string *ret; |
INT_TYPE len, e; |
get_all_args("random_string",args,"%+",&len); |
ret = begin_shared_string(len); |
|
|
|
|
len -= sizeof(INT32)-1; |
for(e=0;e<len;e+=sizeof(INT32)) |
((unsigned INT32 *)(ret->str+e))[0] = DO_NOT_WARN(my_rand()); |
len += sizeof(INT32)-1; |
for(;e<len;e++) |
ret->str[e] = DO_NOT_WARN((char)my_rand()); |
|
pop_n_elems(args); |
push_string(end_shared_string(ret)); |
} |
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_random_seed(INT32 args) |
{ |
INT_TYPE i; |
check_all_args("random_seed",args,BIT_INT | BIT_OBJECT, 0); |
|
if(TYPEOF(Pike_sp[-args]) == T_INT) |
{ |
i=Pike_sp[-args].u.integer; |
}else{ |
i=hash_svalue(Pike_sp-args); |
} |
my_srand(i); |
pop_n_elems(args); |
} |
|
|
|
|
|
|
|
|
|
|
|
void f_query_num_arg(INT32 args) |
{ |
pop_n_elems(args); |
push_int(Pike_fp ? Pike_fp->args : 0); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_search(INT32 args) |
{ |
ptrdiff_t start; |
|
if(args < 2) |
SIMPLE_TOO_FEW_ARGS_ERROR("search", 2); |
|
switch(TYPEOF(Pike_sp[-args])) |
{ |
case T_STRING: |
{ |
struct pike_string *haystack = Pike_sp[-args].u.string; |
|
start=0; |
if(args > 2) |
{ |
if(TYPEOF(Pike_sp[2-args]) != T_INT) |
SIMPLE_BAD_ARG_ERROR("search", 3, "int"); |
|
start=Pike_sp[2-args].u.integer; |
if(start<0) { |
bad_arg_error("search", Pike_sp-args, args, 3, "int(0..)", Pike_sp+2-args, |
"Start must be greater or equal to zero.\n"); |
} |
} |
|
if(haystack->len < start) |
bad_arg_error("search", Pike_sp-args, args, 3, "int(0..)", Pike_sp-args, |
"Start must not be greater than the " |
"length of the string.\n"); |
|
if ((TYPEOF(Pike_sp[1-args]) == T_INT) || |
((TYPEOF(Pike_sp[1-args]) == T_STRING) && |
(Pike_sp[1-args].u.string->len == 1))) { |
INT_TYPE val; |
if (TYPEOF(Pike_sp[1-args]) == T_INT) { |
val = Pike_sp[1-args].u.integer; |
} else { |
val = index_shared_string(Pike_sp[1-args].u.string, 0); |
} |
|
if( !string_range_contains( haystack, val ) ) |
{ |
pop_n_elems(args); |
push_int( -1 ); |
return; |
} |
switch(Pike_sp[-args].u.string->size_shift) { |
case 0: |
{ |
p_wchar0 *str = STR0(haystack); |
if (val >= 256) { |
start = -1; |
break; |
} |
while (start < haystack->len) { |
if (str[start] == val) break; |
start++; |
} |
} |
break; |
case 1: |
{ |
p_wchar1 *str = STR1(haystack); |
if (val >= 65536) { |
start = -1; |
break; |
} |
while (start < haystack->len) { |
if (str[start] == val) break; |
start++; |
} |
} |
break; |
case 2: |
{ |
p_wchar2 *str = STR2(haystack); |
while (start < haystack->len) { |
if (str[start] == (p_wchar2)val) break; |
start++; |
} |
} |
break; |
#ifdef PIKE_DEBUG |
default: |
Pike_fatal("search(): Unsupported string shift: %d!\n", |
haystack->size_shift); |
break; |
#endif |
} |
if (start >= haystack->len) { |
start = -1; |
} |
} else if(TYPEOF(Pike_sp[1-args]) == T_STRING) { |
|
if (Pike_sp[1-args].u.string->len) { |
start = string_search(haystack, |
Pike_sp[1-args].u.string, |
start); |
} |
} else { |
SIMPLE_BAD_ARG_ERROR("search", 2, "string | int"); |
} |
pop_n_elems(args); |
push_int64(start); |
break; |
} |
|
case T_ARRAY: |
start=0; |
if(args > 2) |
{ |
if(TYPEOF(Pike_sp[2-args]) != T_INT) |
SIMPLE_BAD_ARG_ERROR("search", 3, "int"); |
|
start=Pike_sp[2-args].u.integer; |
if(start<0) { |
bad_arg_error("search", Pike_sp-args, args, 3, "int(0..)", Pike_sp+2-args, |
"Start must be greater or equal to zero.\n"); |
} |
} |
start=array_search(Pike_sp[-args].u.array,Pike_sp+1-args,start); |
pop_n_elems(args); |
push_int64(start); |
break; |
|
case T_MAPPING: |
if(args > 2) { |
mapping_search_no_free(Pike_sp,Pike_sp[-args].u.mapping,Pike_sp+1-args,Pike_sp+2-args); |
} else { |
mapping_search_no_free(Pike_sp,Pike_sp[-args].u.mapping,Pike_sp+1-args,0); |
} |
free_svalue(Pike_sp-args); |
Pike_sp[-args]=*Pike_sp; |
dmalloc_touch_svalue(Pike_sp); |
pop_n_elems(args-1); |
return; |
|
case T_OBJECT: |
{ |
struct program *p; |
if ((p = (Pike_sp[-args].u.object->prog))) { |
struct object *o = Pike_sp[-args].u.object; |
int id_level = p->inherits[SUBTYPEOF(Pike_sp[-args])].identifier_level; |
int id; |
int next, ind; |
p = p->inherits[SUBTYPEOF(Pike_sp[-args])].prog; |
|
|
id = low_find_lfun(p, LFUN__SEARCH); |
|
if (id >= 0) { |
apply_low(o, id + id_level, args-1); |
stack_pop_n_elems_keep_top(1); |
return; |
} |
|
|
if (((id = find_identifier("value", p)) >= 0) && |
((next = find_identifier("next", p)) >= 0) && |
((ind = find_identifier("index", p)) >= 0)) { |
|
|
id += id_level; |
next += id_level; |
ind += id_level; |
|
|
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(); |
} |
|
|
|
while(1) { |
apply_low(o, id, 0); |
if (is_eq(Pike_sp-2, Pike_sp-1)) { |
|
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)) { |
|
pop_n_elems(4); |
|
|
|
push_undefined(); |
return; |
} |
pop_n_elems(2); |
} |
} |
} |
} |
|
default: |
SIMPLE_BAD_ARG_ERROR("search", 1, "string|array|mapping|object"); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_has_prefix(INT32 args) |
{ |
struct pike_string *a, *b; |
|
if(args<2) |
SIMPLE_TOO_FEW_ARGS_ERROR("has_prefix", 2); |
if((TYPEOF(Pike_sp[-args]) != T_STRING) && |
(TYPEOF(Pike_sp[-args]) != T_OBJECT)) |
SIMPLE_ARG_TYPE_ERROR("has_prefix", 1, "string|object"); |
if(TYPEOF(Pike_sp[1-args]) != T_STRING) |
SIMPLE_ARG_TYPE_ERROR("has_prefix", 2, "string"); |
|
b = Pike_sp[1-args].u.string; |
|
if (TYPEOF(Pike_sp[-args]) == T_OBJECT) { |
ptrdiff_t i; |
struct object *o = Pike_sp[-args].u.object; |
int inherit_no = SUBTYPEOF(Pike_sp[-args]); |
|
if (!o->prog || FIND_LFUN(o->prog, LFUN__SIZEOF) < 0) { |
Pike_error("has_prefix(): Object in argument 1 lacks lfun::_sizeof().\n"); |
} |
|
apply_lfun(o, LFUN__SIZEOF, 0); |
if ((TYPEOF(Pike_sp[-1]) != T_INT) || (Pike_sp[-1].u.integer < b->len)) { |
pop_n_elems(args + 1); |
push_int(0); |
return; |
} |
|
for (i = 0; i < b->len; i++) { |
p_wchar2 ch = index_shared_string(b, i); |
Pike_sp[-1].u.integer = i; |
|
object_index_no_free(Pike_sp-1, o, inherit_no, Pike_sp-1); |
if (TYPEOF(Pike_sp[-1]) != PIKE_T_INT) { |
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; |
} |
} |
pop_n_elems(args+1); |
push_int(1); |
return; |
} |
|
a = Pike_sp[-args].u.string; |
|
|
if ((b->len > a->len) || (b->size_shift > a->size_shift) |
|| !string_range_contains_string(a, b)) { |
pop_n_elems(args); |
push_int(0); |
return; |
} |
|
|
if ((a == b)||(!b->len)) { |
pop_n_elems(args); |
push_int(1); |
return; |
} |
|
if (a->size_shift == b->size_shift) { |
int res = !MEMCMP(a->str, b->str, b->len << b->size_shift); |
pop_n_elems(args); |
push_int(res); |
return; |
} |
|
|
#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); \ |
ptrdiff_t len = b->len; \ |
while(len-- && (s1[len] == s2[len])) \ |
; \ |
pop_n_elems(args); \ |
push_int(len == -1); \ |
return; \ |
} \ |
break |
|
CASE_SHIFT(1,0); |
CASE_SHIFT(2,0); |
CASE_SHIFT(2,1); |
default: |
Pike_error("has_prefix(): Unexpected string shift combination: a:%d, b:%d!\n", |
a->size_shift, b->size_shift); |
break; |
} |
#undef CASE_SHIFT |
#undef TWO_SHIFTS |
} |
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_has_suffix(INT32 args) |
{ |
struct pike_string *a, *b; |
|
if(args<2) |
SIMPLE_TOO_FEW_ARGS_ERROR("has_suffix", 2); |
if(TYPEOF(Pike_sp[-args]) != T_STRING) |
SIMPLE_ARG_TYPE_ERROR("has_suffix", 1, "string"); |
if(TYPEOF(Pike_sp[1-args]) != T_STRING) |
SIMPLE_ARG_TYPE_ERROR("has_suffix", 2, "string"); |
|
a = Pike_sp[-args].u.string; |
b = Pike_sp[1-args].u.string; |
|
|
if ((b->len > a->len) || (b->size_shift > a->size_shift) |
|| !string_range_contains_string(a, b)) { |
pop_n_elems(args); |
push_int(0); |
return; |
} |
|
|
if ((a == b)||(!b->len)) { |
pop_n_elems(args); |
push_int(1); |
return; |
} |
|
if (a->size_shift == b->size_shift) { |
int res = !MEMCMP(a->str + ((a->len - b->len)<<b->size_shift), b->str, |
b->len << b->size_shift); |
pop_n_elems(args); |
push_int(res); |
return; |
} |
|
|
#define TWO_SHIFTS(S1, S2) ((S1)|((S2)<<2)) |
switch(TWO_SHIFTS(a->size_shift, b->size_shift)) { |
#define CASE_SHIFT(S1, S2) \ |
case TWO_SHIFTS(S1, S2): \ |
{ \ |
PIKE_CONCAT(p_wchar,S1) *s1 = PIKE_CONCAT(STR,S1)(a) + a->len - b->len; \ |
PIKE_CONCAT(p_wchar,S2) *s2 = PIKE_CONCAT(STR,S2)(b); \ |
ptrdiff_t len = b->len; \ |
while(len-- && (s1[len] == s2[len])) \ |
; \ |
pop_n_elems(args); \ |
push_int(len == -1); \ |
return; \ |
} \ |
break |
|
CASE_SHIFT(1,0); |
CASE_SHIFT(2,0); |
CASE_SHIFT(2,1); |
default: |
Pike_error("has_prefix(): Unexpected string shift combination: a:%d, b:%d!\n", |
a->size_shift, b->size_shift); |
break; |
} |
#undef CASE_SHIFT |
#undef TWO_SHIFTS |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_has_index(INT32 args) |
{ |
int t = 0; |
|
if(args < 2) |
SIMPLE_TOO_FEW_ARGS_ERROR("has_index", 2); |
if(args > 2) |
pop_n_elems(args-2); |
|
switch(TYPEOF(Pike_sp[-2])) |
{ |
case T_STRING: |
if(TYPEOF(Pike_sp[-1]) == T_INT) |
t = (0 <= Pike_sp[-1].u.integer && Pike_sp[-1].u.integer < Pike_sp[-2].u.string->len); |
|
pop_n_elems(args); |
push_int(t); |
break; |
|
case T_ARRAY: |
if(TYPEOF(Pike_sp[-1]) == T_INT) |
t = (0 <= Pike_sp[-1].u.integer && Pike_sp[-1].u.integer < Pike_sp[-2].u.array->size); |
|
pop_n_elems(args); |
push_int(t); |
break; |
|
case T_MULTISET: |
case T_MAPPING: |
f_index(2); |
f_zero_type(1); |
|
#ifdef PIKE_DEBUG |
if(TYPEOF(Pike_sp[-1]) != T_INT) |
PIKE_ERROR("has_index", |
"Function `zero_type' gave incorrect result.\n", Pike_sp, args); |
#endif |
Pike_sp[-1].u.integer = !Pike_sp[-1].u.integer; |
break; |
|
case T_OBJECT: |
case T_PROGRAM: |
|
|
|
|
|
|
|
|
|
|
|
stack_swap(); |
f_indices(1); |
stack_swap(); |
f_search(2); |
|
if(TYPEOF(Pike_sp[-1]) == T_INT) |
Pike_sp[-1].u.integer = (Pike_sp[-1].u.integer != -1); |
else |
PIKE_ERROR("has_index", |
"Function `search' gave incorrect result.\n", Pike_sp, args); |
break; |
|
default: |
SIMPLE_ARG_TYPE_ERROR ("has_index", 1, |
"string|array|mapping|multiset|object|program"); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_has_value(INT32 args) |
{ |
if(args < 2) |
SIMPLE_TOO_FEW_ARGS_ERROR("has_value", 2); |
if(args > 2) |
pop_n_elems(args-2); |
|
switch(TYPEOF(Pike_sp[-2])) |
{ |
case T_MAPPING: |
f_search(2); |
f_zero_type(1); |
|
if(TYPEOF(Pike_sp[-1]) == T_INT) |
Pike_sp[-1].u.integer = !Pike_sp[-1].u.integer; |
else |
PIKE_ERROR("has_value", |
"Function `zero_type' gave incorrect result.\n", Pike_sp, args); |
break; |
|
case T_PROGRAM: |
case T_OBJECT: |
|
|
|
|
|
|
|
|
|
|
|
|
case T_MULTISET: |
|
|
stack_swap(); |
f_values(1); |
stack_swap(); |
|
|
|
case T_STRING: |
case T_ARRAY: |
f_search(2); |
|
if(TYPEOF(Pike_sp[-1]) == T_INT) |
Pike_sp[-1].u.integer = (Pike_sp[-1].u.integer != -1); |
else |
PIKE_ERROR("has_value", "Search gave incorrect result.\n", Pike_sp, args); |
break; |
|
default: |
SIMPLE_ARG_TYPE_ERROR ("has_value", 1, "string|array|mapping|object|program"); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_add_constant(INT32 args) |
{ |
ASSERT_SECURITY_ROOT("add_constant"); |
|
if(args<1) |
SIMPLE_TOO_FEW_ARGS_ERROR("add_constant", 1); |
|
if(TYPEOF(Pike_sp[-args]) != T_STRING) |
SIMPLE_BAD_ARG_ERROR("add_constant", 1, "string"); |
|
if(args>1) |
{ |
dmalloc_touch_svalue(Pike_sp-args+1); |
low_add_efun(Pike_sp[-args].u.string, Pike_sp-args+1); |
}else{ |
low_add_efun(Pike_sp[-args].u.string, 0); |
} |
pop_n_elems(args); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define NT_COMBINE_PATH |
#include "combine_path.h" |
|
#define UNIX_COMBINE_PATH |
#include "combine_path.h" |
|
#define AMIGAOS_COMBINE_PATH |
#include "combine_path.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_zero_type(INT32 args) |
{ |
if(args < 1) |
SIMPLE_TOO_FEW_ARGS_ERROR("zero_type",1); |
|
if((TYPEOF(Pike_sp[-args]) == T_OBJECT || |
TYPEOF(Pike_sp[-args]) == T_FUNCTION) |
&& !Pike_sp[-args].u.object->prog) |
{ |
pop_n_elems(args); |
push_int(NUMBER_DESTRUCTED); |
} |
else if(TYPEOF(Pike_sp[-args]) != T_INT) |
{ |
pop_n_elems(args); |
push_int(0); |
} |
else |
{ |
pop_n_elems(args-1); |
Pike_sp[-1].u.integer = SUBTYPEOF(Pike_sp[-1]); |
SET_SVAL_SUBTYPE(Pike_sp[-1], NUMBER_NUMBER); |
} |
} |
|
static int generate_zero_type(node *n) |
{ |
struct compilation *c = THIS_COMPILATION; |
CHECK_COMPILER(); |
if(count_args(CDR(n)) != 1) return 0; |
if(do_docode(CDR(n),DO_NOT_COPY) != 1) |
Pike_fatal("Count args was wrong in generate_zero_type().\n"); |
emit0(F_ZERO_TYPE); |
return 1; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_string_to_unicode(INT32 args) |
{ |
struct pike_string *in; |
struct pike_string *out = NULL; |
ptrdiff_t len; |
ptrdiff_t i; |
|
get_all_args("string_to_unicode", args, "%W", &in); |
|
switch(in->size_shift) { |
case 0: |
|
len = in->len * 2; |
out = begin_shared_string(len); |
if (len) { |
MEMSET(out->str, 0, len); |
#ifdef PIKE_DEBUG |
if (d_flag) { |
for(i = len; i--;) { |
if (out->str[i]) { |
Pike_fatal("MEMSET didn't clear byte %ld of %ld\n", |
PTRDIFF_T_TO_LONG(i+1), |
PTRDIFF_T_TO_LONG(len)); |
} |
} |
} |
#endif /* PIKE_DEBUG */ |
for(i = in->len; i--;) { |
out->str[i * 2 + 1] = in->str[i]; |
} |
} |
out = end_shared_string(out); |
break; |
case 1: |
|
|
len = in->len * 2; |
out = begin_shared_string(len); |
#if (PIKE_BYTEORDER == 4321) |
|
* |
* FIXME: Future optimization: Check if refcount is == 1, |
* and perform sufficient magic to be able to convert in place. |
*/ |
MEMCPY(out->str, in->str, len); |
#else |
|
{ |
p_wchar1 *str1 = STR1(in); |
for(i = in->len; i--;) { |
unsigned INT32 c = str1[i]; |
out->str[i * 2 + 1] = c & 0xff; |
out->str[i * 2] = c >> 8; |
} |
} |
#endif |
out = end_shared_string(out); |
break; |
case 2: |
|
{ |
p_wchar2 *str2 = STR2(in); |
ptrdiff_t j; |
len = in->len * 2; |
|
for(i = in->len; i--;) { |
if (str2[i] > 0xfffd) { |
if (str2[i] < 0x10000) { |
|
|
|
Pike_error("string_to_unicode(): Illegal character 0x%04x (index %ld) " |
"is not a Unicode character.", |
str2[i], PTRDIFF_T_TO_LONG(i)); |
} |
if (str2[i] > 0x10ffff) { |
Pike_error("string_to_unicode(): Character 0x%08x (index %ld) " |
"is out of range (0x00000000..0x0010ffff).", |
str2[i], PTRDIFF_T_TO_LONG(i)); |
} |
|
|
|
len += 2; |
} |
} |
out = begin_shared_string(len); |
j = len; |
for(i = in->len; i--;) { |
unsigned INT32 c = str2[i]; |
|
j -= 2; |
|
if (c > 0xffff) { |
|
c -= 0x10000; |
|
out->str[j + 1] = c & 0xff; |
out->str[j] = 0xdc | ((c >> 8) & 0x03); |
j -= 2; |
c >>= 10; |
c |= 0xd800; |
} |
out->str[j + 1] = c & 0xff; |
out->str[j] = c >> 8; |
} |
#ifdef PIKE_DEBUG |
if (j) { |
Pike_fatal("string_to_unicode(): Indexing error: len:%ld, j:%ld.\n", |
PTRDIFF_T_TO_LONG(len), PTRDIFF_T_TO_LONG(j)); |
} |
#endif /* PIKE_DEBUG */ |
out = end_shared_string(out); |
} |
break; |
#ifdef PIKE_DEBUG |
default: |
Pike_fatal("string_to_unicode(): Bad string shift: %d!\n", in->size_shift); |
break; |
#endif |
} |
pop_n_elems(args); |
push_string(out); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_unicode_to_string(INT32 args) |
{ |
struct pike_string *in; |
struct pike_string *out = NULL; |
ptrdiff_t len, i, num_surrogates = 0; |
int swab=0; |
p_wchar1 surr1, surr2, surrmask, *str0; |
|
get_all_args("unicode_to_string", args, "%S", &in); |
|
if (in->len & 1) { |
bad_arg_error("unicode_to_string", Pike_sp-args, args, 1, "string", Pike_sp-args, |
"String length is odd.\n"); |
} |
|
|
str0 = (p_wchar1 *)in->str; |
len = in->len; |
if (len && (str0[0] == 0xfeff)) { |
|
swab = 0; |
str0 ++; |
len -= 2; |
} else if (len && (str0[0] == 0xfffe)) { |
|
swab = 1; |
str0 ++; |
len -= 2; |
} else { |
|
#if (PIKE_BYTEORDER == 4321) |
swab = 0; |
#else |
swab = 1; |
#endif /* PIKE_BYTEORDER == 4321 */ |
} |
|
|
if (swab) { |
surr1 = 0xd8; |
surr2 = 0xdc; |
surrmask = 0xfc; |
} else { |
surr1 = 0xd800; |
surr2 = 0xdc00; |
surrmask = 0xfc00; |
} |
|
|
for (i = len; i >= 4; i -= 2, str0++) |
if ( (str0[0]&surrmask) == surr1 && |
(str0[1]&surrmask) == surr2 ) |
num_surrogates ++; |
|
|
str0++; |
|
len = len / 2 - num_surrogates; |
|
out = begin_wide_shared_string(len, (num_surrogates? 2 : 1)); |
|
if (!swab) { |
|
if (num_surrogates) { |
|
|
p_wchar2 *str2 = STR2(out); |
|
for (i = len; i--; --str0) |
|
if ((str0[-1]&surrmask) == surr2 && num_surrogates && |
(str0[-2]&surrmask) == surr1) { |
|
str2[i] = ((str0[-2]&0x3ff)<<10) + (str0[-1]&0x3ff) + 0x10000; |
|
--str0; |
--num_surrogates; |
|
} else |
|
str2[i] = str0[-1]; |
|
} else |
|
|
|
|
MEMCPY(out->str, (char *)(str0-len), len*2); |
} else { |
|
|
if (num_surrogates) { |
|
|
p_wchar2 *str2 = STR2(out); |
|
for (i = len; i--; --str0) { |
|
if ((str0[-1]&surrmask) == surr2 && num_surrogates && |
(str0[-2]&surrmask) == surr1) { |
|
#if (PIKE_BYTEORDER == 4321) |
str2[i] = ((((unsigned char *)str0)[-3]&3)<<18) + |
(((unsigned char *)str0)[-4]<<10) + |
((((unsigned char *)str0)[-1]&3)<<8) + |
((unsigned char *)str0)[-2] + |
0x10000; |
#else /* PIKE_BYTEORDER != 4321 */ |
str2[i] = ((((unsigned char *)str0)[-4]&3)<<18) + |
(((unsigned char *)str0)[-3]<<10) + |
((((unsigned char *)str0)[-2]&3)<<8) + |
((unsigned char *)str0)[-1] + |
0x10000; |
#endif /* PIKE_BYTEORDER == 4321 */ |
--str0; |
--num_surrogates; |
|
} else { |
#if (PIKE_BYTEORDER == 4321) |
str2[i] = (((unsigned char *)str0)[-1]<<8) + |
((unsigned char *)str0)[-2]; |
#else /* PIKE_BYTEORDER != 4321 */ |
str2[i] = (((unsigned char *)str0)[-2]<<8) + |
((unsigned char *)str0)[-1]; |
#endif /* PIKE_BYTEORDER == 4321 */ |
} |
} |
} else { |
|
|
p_wchar1 *str1 = STR1(out); |
|
for (i = len; i--; --str0) { |
#if (PIKE_BYTEORDER == 4321) |
str1[i] = (((unsigned char *)str0)[-1]<<8) + |
((unsigned char *)str0)[-2]; |
#else /* PIKE_BYTEORDER != 4321 */ |
str1[i] = (((unsigned char *)str0)[-2]<<8) + |
((unsigned char *)str0)[-1]; |
#endif /* PIKE_BYTEORDER == 4321 */ |
} |
} |
} |
out = end_shared_string(out); |
pop_n_elems(args); |
push_string(out); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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; |
|
if( (max < 0 || min > 0x10ffff) || (max < 0xe000 && min > 0xd7ff) ) |
{ |
|
debug_make_shared_binary_pcharp( repl_char, 1 ); |
push_int( in->len ); |
o_multiply(); |
} |
else |
{ |
|
|
|
|
struct string_builder out; |
|
|
|
|
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 ) ); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PMOD_EXPORT void f_string_to_utf8(INT32 args) |
{ |
ptrdiff_t len; |
struct pike_string *in; |
|