|
|
|
|
|
|
#include "global.h" |
#include <math.h> |
#include <ctype.h> |
#include "interpret.h" |
#include "svalue.h" |
#include "array.h" |
#include "stralloc.h" |
#include "mapping.h" |
#include "multiset.h" |
#include "opcodes.h" |
#include "object.h" |
#include "error.h" |
#include "pike_types.h" |
#include "pike_memory.h" |
#include "fd_control.h" |
#include "cyclic.h" |
#include "builtin_functions.h" |
#include "module_support.h" |
#include "security.h" |
#include "bignum.h" |
|
RCSID("$Id: opcodes.c,v 1.62 1999/10/31 22:41:44 grubba Exp $"); |
|
void index_no_free(struct svalue *to,struct svalue *what,struct svalue *ind) |
{ |
INT32 i; |
|
#ifdef PIKE_SECURITY |
if(what->type <= MAX_COMPLEX) |
if(!CHECK_DATA_SECURITY(what->u.array, SECURITY_BIT_INDEX)) |
error("Index permission denied.\n"); |
#endif |
|
switch(what->type) |
{ |
#ifdef AUTO_BIGNUM |
case T_INT: |
convert_svalue_to_bignum(what); |
index_no_free(to, what, ind); |
if(IS_UNDEFINED(to)) |
error("Indexing an integer with unknown method.\n"); |
break; |
#endif /* AUTO_BIGNUM */ |
|
case T_ARRAY: |
simple_array_index_no_free(to,what->u.array,ind); |
break; |
|
case T_MAPPING: |
mapping_index_no_free(to,what->u.mapping,ind); |
break; |
|
case T_OBJECT: |
object_index_no_free(to, what->u.object, ind); |
break; |
|
case T_MULTISET: |
i=multiset_member(what->u.multiset, ind); |
to->type=T_INT; |
to->subtype=i ? NUMBER_UNDEFINED : 0; |
to->u.integer=i; |
break; |
|
case T_STRING: |
if(ind->type==T_INT) |
{ |
i=ind->u.integer; |
if(i<0) |
i+=what->u.string->len; |
if(i<0 || i>=what->u.string->len) |
{ |
if(what->u.string->len == 0) |
error("Attempt to index the empty string with %d.\n", i); |
else |
error("Index %d is out of string range 0 - %d.\n", |
i, what->u.string->len-1); |
} else |
i=index_shared_string(what->u.string,i); |
to->type=T_INT; |
to->subtype=NUMBER_NUMBER; |
to->u.integer=i; |
break; |
}else{ |
error("Index is not an integer.\n"); |
} |
|
case T_PROGRAM: |
program_index_no_free(to, what->u.program, ind); |
break; |
|
case T_FUNCTION: |
{ |
struct program *p = program_from_svalue(what); |
if (p) { |
program_index_no_free(to, p, ind); |
break; |
} |
} |
|
|
default: |
error("Indexing a basic type.\n"); |
} |
} |
|
void o_index(void) |
{ |
struct svalue s; |
index_no_free(&s,sp-2,sp-1); |
pop_n_elems(2); |
*sp=s; |
dmalloc_touch_svalue(sp); |
sp++; |
} |
|
void o_cast(struct pike_string *type, INT32 run_time_type) |
{ |
INT32 i; |
|
if(run_time_type != sp[-1].type) |
{ |
if(run_time_type == T_MIXED) |
return; |
|
if(sp[-1].type == T_OBJECT) |
{ |
struct pike_string *s; |
s=describe_type(type); |
push_string(s); |
if(!sp[-2].u.object->prog) |
error("Cast called on destructed object.\n"); |
if(FIND_LFUN(sp[-2].u.object->prog,LFUN_CAST) == -1) |
error("No cast method in object.\n"); |
apply_lfun(sp[-2].u.object, LFUN_CAST, 1); |
free_svalue(sp-2); |
sp[-2]=sp[-1]; |
sp--; |
dmalloc_touch_svalue(sp); |
}else |
|
switch(run_time_type) |
{ |
default: |
error("Cannot perform cast to that type.\n"); |
|
case T_MIXED: |
return; |
|
case T_MAPPING: |
switch(sp[-1].type) |
{ |
case T_ARRAY: |
{ |
f_transpose(1); |
sp--; |
dmalloc_touch_svalue(sp); |
push_array_items(sp->u.array); |
f_mkmapping(2); |
break; |
} |
|
default: |
error("Cannot cast %s to mapping.\n",get_name_of_type(sp[-1].type)); |
} |
break; |
|
case T_ARRAY: |
switch(sp[-1].type) |
{ |
case T_MAPPING: |
{ |
struct array *a=mapping_to_array(sp[-1].u.mapping); |
pop_stack(); |
push_array(a); |
break; |
} |
|
case T_STRING: |
f_values(1); |
break; |
|
case T_MULTISET: |
f_indices(1); |
break; |
|
default: |
error("Cannot cast %s to array.\n",get_name_of_type(sp[-1].type)); |
|
} |
break; |
|
case T_INT: |
switch(sp[-1].type) |
{ |
case T_FLOAT: |
i=(int)(sp[-1].u.float_number); |
#ifdef AUTO_BIGNUM |
if((i < 0 ? -i : i) < floor(fabs(sp[-1].u.float_number))) |
{ |
|
|
convert_stack_top_to_bignum(); |
return; |
|
|
|
|
} |
else |
#endif /* AUTO_BIGNUM */ |
{ |
sp[-1].type=T_INT; |
sp[-1].u.integer=i; |
} |
break; |
|
case T_STRING: |
|
|
|
#ifdef AUTO_BIGNUM |
convert_stack_top_string_to_inumber(10); |
return; |
|
|
|
|
#else |
i=STRTOL(sp[-1].u.string->str,0,10); |
free_string(sp[-1].u.string); |
sp[-1].type=T_INT; |
sp[-1].u.integer=i; |
#endif /* AUTO_BIGNUM */ |
break; |
|
default: |
error("Cannot cast %s to int.\n",get_name_of_type(sp[-1].type)); |
} |
|
break; |
|
case T_FLOAT: |
{ |
FLOAT_TYPE f = 0.0; |
|
switch(sp[-1].type) |
{ |
case T_INT: |
f=(FLOAT_TYPE)(sp[-1].u.integer); |
break; |
|
case T_STRING: |
f=STRTOD(sp[-1].u.string->str,0); |
free_string(sp[-1].u.string); |
break; |
|
default: |
error("Cannot cast %s to float.\n",get_name_of_type(sp[-1].type)); |
} |
|
sp[-1].type=T_FLOAT; |
sp[-1].u.float_number=f; |
break; |
} |
|
case T_STRING: |
{ |
char buf[200]; |
switch(sp[-1].type) |
{ |
case T_INT: |
sprintf(buf,"%ld",(long)sp[-1].u.integer); |
break; |
|
case T_FLOAT: |
sprintf(buf,"%f",(double)sp[-1].u.float_number); |
break; |
|
case T_ARRAY: |
{ |
int i; |
struct array *a = sp[-1].u.array; |
struct pike_string *s; |
int shift = 0; |
|
for(i = a->size; i--; ) { |
unsigned INT32 val; |
if (a->item[i].type != T_INT) { |
error("cast: Item %d is not an integer.\n", i); |
} |
val = (unsigned INT32)a->item[i].u.integer; |
if (val > 0xff) { |
shift = 1; |
if (val > 0xffff) { |
shift = 2; |
break; |
} |
while(i--) { |
if (a->item[i].type != T_INT) { |
error("cast: Item %d is not an integer.\n", i); |
} |
val = (unsigned INT32)a->item[i].u.integer; |
if (val > 0xffff) { |
shift = 2; |
break; |
} |
} |
break; |
} |
} |
s = begin_wide_shared_string(a->size, shift); |
switch(shift) { |
case 0: |
for(i = a->size; i--; ) { |
s->str[i] = a->item[i].u.integer; |
} |
break; |
case 1: |
{ |
p_wchar1 *str1 = STR1(s); |
for(i = a->size; i--; ) { |
str1[i] = a->item[i].u.integer; |
} |
} |
break; |
case 2: |
{ |
p_wchar2 *str2 = STR2(s); |
for(i = a->size; i--; ) { |
str2[i] = a->item[i].u.integer; |
} |
} |
break; |
default: |
free_string(end_shared_string(s)); |
fatal("cast: Bad shift: %d.\n", shift); |
break; |
} |
s = end_shared_string(s); |
pop_stack(); |
push_string(s); |
return; |
} |
break; |
|
default: |
error("Cannot cast %s to string.\n",get_name_of_type(sp[-1].type)); |
} |
|
sp[-1].type=T_STRING; |
sp[-1].u.string=make_shared_string(buf); |
break; |
} |
|
case T_OBJECT: |
switch(sp[-1].type) |
{ |
case T_STRING: |
if(fp->pc) |
{ |
INT32 lineno; |
push_text(get_line(fp->pc, fp->context.prog, &lineno)); |
}else{ |
push_int(0); |
} |
APPLY_MASTER("cast_to_object",2); |
return; |
|
case T_FUNCTION: |
sp[-1].type = T_OBJECT; |
break; |
|
default: |
error("Cannot cast %s to object.\n",get_name_of_type(sp[-1].type)); |
} |
break; |
|
case T_PROGRAM: |
switch(sp[-1].type) |
{ |
case T_STRING: |
if(fp->pc) |
{ |
INT32 lineno; |
push_text(get_line(fp->pc, fp->context.prog, &lineno)); |
}else{ |
push_int(0); |
} |
APPLY_MASTER("cast_to_program",2); |
return; |
|
case T_FUNCTION: |
{ |
struct program *p=program_from_function(sp-1); |
if(p) |
{ |
add_ref(p); |
pop_stack(); |
push_program(p); |
}else{ |
pop_stack(); |
push_int(0); |
} |
} |
return; |
|
default: |
error("Cannot cast %s to a program.\n",get_name_of_type(sp[-1].type)); |
} |
} |
} |
|
if(run_time_type != sp[-1].type) |
{ |
if(sp[-1].type == T_OBJECT && sp[-1].u.object->prog) |
{ |
int f=FIND_LFUN(sp[-1].u.object->prog, LFUN__IS_TYPE); |
if( f != -1) |
{ |
push_text(get_name_of_type(run_time_type)); |
apply_low(sp[-2].u.object, f, 1); |
f=!IS_ZERO(sp-1); |
pop_stack(); |
if(f) goto emulated_type_ok; |
} |
} |
error("Cast failed, wanted %s, got %s\n", |
get_name_of_type(run_time_type), |
get_name_of_type(sp[-1].type)); |
} |
|
emulated_type_ok: |
|
if (!type) return; |
|
switch(run_time_type) |
{ |
case T_ARRAY: |
{ |
struct pike_string *itype; |
INT32 run_time_itype; |
|
push_string(itype=index_type(type,0)); |
run_time_itype=compile_type_to_runtime_type(itype); |
|
if(run_time_itype != T_MIXED) |
{ |
struct array *a; |
struct array *tmp=sp[-2].u.array; |
DECLARE_CYCLIC(); |
|
if((a=(struct array *)BEGIN_CYCLIC(tmp,0))) |
{ |
ref_push_array(a); |
}else{ |
INT32 e,i; |
#ifdef PIKE_DEBUG |
struct svalue *save_sp=sp+1; |
#endif |
push_array(a=allocate_array(tmp->size)); |
SET_CYCLIC_RET(a); |
|
for(e=0;e<a->size;e++) |
{ |
push_svalue(tmp->item+e); |
o_cast(itype, run_time_itype); |
array_set_index(a,e,sp-1); |
pop_stack(); |
} |
#ifdef PIKE_DEBUG |
if(save_sp!=sp) |
fatal("o_cast left stack droppings.\n"); |
#endif |
END_CYCLIC(); |
} |
assign_svalue(sp-3,sp-1); |
pop_stack(); |
} |
pop_stack(); |
} |
break; |
|
case T_MULTISET: |
{ |
struct pike_string *itype; |
INT32 run_time_itype; |
|
push_string(itype=key_type(type,0)); |
run_time_itype=compile_type_to_runtime_type(itype); |
|
if(run_time_itype != T_MIXED) |
{ |
struct multiset *m; |
struct array *tmp=sp[-2].u.multiset->ind; |
DECLARE_CYCLIC(); |
|
if((m=(struct multiset *)BEGIN_CYCLIC(tmp,0))) |
{ |
ref_push_multiset(m); |
}else{ |
INT32 e,i; |
struct array *a; |
#ifdef PIKE_DEBUG |
struct svalue *save_sp=sp+1; |
#endif |
push_multiset(m=allocate_multiset(a=allocate_array(tmp->size))); |
|
SET_CYCLIC_RET(m); |
|
for(e=0;e<a->size;e++) |
{ |
push_svalue(tmp->item+e); |
o_cast(itype, run_time_itype); |
array_set_index(a,e,sp-1); |
pop_stack(); |
} |
#ifdef PIKE_DEBUG |
if(save_sp!=sp) |
fatal("o_cast left stack droppings.\n"); |
#endif |
order_multiset(m); |
END_CYCLIC(); |
} |
assign_svalue(sp-3,sp-1); |
pop_stack(); |
} |
pop_stack(); |
} |
break; |
|
case T_MAPPING: |
{ |
struct pike_string *itype,*vtype; |
INT32 run_time_itype; |
INT32 run_time_vtype; |
|
push_string(itype=key_type(type,0)); |
run_time_itype=compile_type_to_runtime_type(itype); |
|
push_string(vtype=index_type(type,0)); |
run_time_vtype=compile_type_to_runtime_type(vtype); |
|
if(run_time_itype != T_MIXED || |
run_time_vtype != T_MIXED) |
{ |
struct mapping *m; |
struct mapping *tmp=sp[-3].u.mapping; |
DECLARE_CYCLIC(); |
|
if((m=(struct mapping *)BEGIN_CYCLIC(tmp,0))) |
{ |
ref_push_mapping(m); |
}else{ |
INT32 e,i; |
struct keypair *k; |
#ifdef PIKE_DEBUG |
struct svalue *save_sp=sp+1; |
#endif |
push_mapping(m=allocate_mapping(tmp->size)); |
|
SET_CYCLIC_RET(m); |
|
MAPPING_LOOP(tmp) |
{ |
push_svalue(& k->ind); |
o_cast(itype, run_time_itype); |
push_svalue(& k->val); |
o_cast(vtype, run_time_vtype); |
mapping_insert(m,sp-2,sp-1); |
pop_n_elems(2); |
} |
#ifdef PIKE_DEBUG |
if(save_sp!=sp) |
fatal("o_cast left stack droppings.\n"); |
#endif |
END_CYCLIC(); |
} |
assign_svalue(sp-4,sp-1); |
pop_stack(); |
} |
pop_n_elems(2); |
} |
} |
} |
|
|
void f_cast(void) |
{ |
#ifdef PIKE_DEBUG |
struct svalue *save_sp=sp; |
if(sp[-2].type != T_STRING) |
fatal("Cast expression destroyed stack or left droppings!\n"); |
#endif |
o_cast(sp[-2].u.string, |
compile_type_to_runtime_type(sp[-2].u.string)); |
#ifdef PIKE_DEBUG |
if(save_sp != sp) |
fatal("Internal error: o_cast() left droppings on stack.\n"); |
#endif |
free_svalue(sp-2); |
sp[-2]=sp[-1]; |
sp--; |
dmalloc_touch_svalue(sp); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int read_set(unsigned char *match,int cnt,char *set,int match_len) |
{ |
int init; |
int last=0; |
int e; |
|
if(cnt>=match_len) |
error("Error in sscanf format string.\n"); |
|
if(match[cnt]=='^') |
{ |
for(e=0;e<256;e++) set[e]=1; |
init=0; |
cnt++; |
if(cnt>=match_len) |
error("Error in sscanf format string.\n"); |
}else{ |
for(e=0;e<256;e++) set[e]=0; |
init=1; |
} |
if(match[cnt]==']' || match[cnt]=='-') |
{ |
set[last=match[cnt]]=init; |
cnt++; |
if(cnt>=match_len) |
error("Error in sscanf format string.\n"); |
} |
|
for(;match[cnt]!=']';cnt++) |
{ |
if(match[cnt]=='-') |
{ |
cnt++; |
if(cnt>=match_len) |
error("Error in sscanf format string.\n"); |
if(match[cnt]==']') |
{ |
set['-']=init; |
break; |
} |
for(e=last;e<(int) EXTRACT_UCHAR(match+cnt);e++) set[e]=init; |
} |
set[last=EXTRACT_UCHAR(match+cnt)]=init; |
} |
return cnt; |
} |
|
|
|
|
|
|
#ifndef FLOAT_IS_IEEE_BIG |
#ifndef FLOAT_IS_IEEE_LITTLE |
#define NEED_CUSTOM_IEEE |
#endif |
#endif |
#ifndef NEED_CUSTOM_IEEE |
#ifndef DOUBLE_IS_IEEE_BIG |
#ifndef DOUBLE_IS_IEEE_LITTLE |
#define NEED_CUSTOM_IEEE |
#endif |
#endif |
#endif |
|
#ifdef NEED_CUSTOM_IEEE |
|
#if HAVE_LDEXP |
#define LDEXP ldexp |
#else |
extern double LDEXP(double x, int exp); |
#endif |
|
static INLINE float low_parse_IEEE_float(char *b, int sz) |
{ |
unsigned INT32 f, extra_f; |
int s, e; |
unsigned char x[4]; |
double r; |
|
x[0] = EXTRACT_UCHAR(b); |
x[1] = EXTRACT_UCHAR(b+1); |
x[2] = EXTRACT_UCHAR(b+2); |
x[3] = EXTRACT_UCHAR(b+3); |
s = ((x[0]&0x80)? 1 : 0); |
|
if(sz==4) { |
e = (((int)(x[0]&0x7f))<<1)|((x[1]&0x80)>>7); |
f = (((unsigned INT32)(x[1]&0x7f))<<16)|(((unsigned INT32)x[2])<<8)|x[3]; |
extra_f = 0; |
if(e==255) |
e = 9999; |
else if(e>0) { |
f |= 0x00800000; |
e -= 127+23; |
} else |
e -= 126+23; |
} else { |
e = (((int)(x[0]&0x7f))<<4)|((x[1]&0xf0)>>4); |
f = (((unsigned INT32)(x[1]&0x0f))<<16)|(((unsigned INT32)x[2])<<8)|x[3]; |
extra_f = (((unsigned INT32)EXTRACT_UCHAR(b+4))<<24)| |
(((unsigned INT32)EXTRACT_UCHAR(b+5))<<16)| |
(((unsigned INT32)EXTRACT_UCHAR(b+6))<<8)| |
((unsigned INT32)EXTRACT_UCHAR(b+7)); |
if(e==2047) |
e = 9999; |
else if(e>0) { |
f |= 0x00100000; |
e -= 1023+20; |
} else |
e -= 1022+20; |
} |
if(e>=9999) |
if(f||extra_f) { |
|
|
|
|
return (float)0.0; |
} else { |
|
#ifdef HUGE_VAL |
return (float)(s? -HUGE_VAL:HUGE_VAL); |
#else |
|
e = 1024; |
f = 1; |
extra_f = 0; |
#endif |
} |
|
r = (double)f; |
if(extra_f) |
r += ((double)extra_f)/4294967296.0; |
return (float)(s? -LDEXP(r, e):LDEXP(r, e)); |
} |
|
#endif |
|
#ifdef PIKE_DEBUG |
#define DO_IF_DEBUG(X) X |
#else /* !PIKE_DEBUG */ |
#define DO_IF_DEBUG(X) |
#endif /* PIKE_DEBUG */ |
|
#ifdef AUTO_BIGNUM |
#define DO_IF_BIGNUM(X) X |
#else /* !AUTO_BIGNUM */ |
#define DO_IF_BIGNUM(X) |
#endif /* AUTO_BIGNUM */ |
|
#ifdef __CHECKER__ |
#define DO_IF_CHECKER(X) X |
#else /* !__CHECKER__ */ |
#define DO_IF_CHECKER(X) |
#endif /* __CHECKER__ */ |
|
#ifdef FLOAT_IS_IEEE_BIG |
#define EXTRACT_FLOAT(SVAL, INPUT, SHIFT) \ |
do { \ |
float f; \ |
((char *)&f)[0] = *((INPUT)); \ |
((char *)&f)[1] = *((INPUT)+1); \ |
((char *)&f)[2] = *((INPUT)+2); \ |
((char *)&f)[3] = *((INPUT)+3); \ |
(SVAL).u.float_number = f; \ |
} while(0) |
#else |
#ifdef FLOAT_IS_IEEE_LITTLE |
#define EXTRACT_FLOAT(SVAL, INPUT, SHIFT) \ |
do { \ |
float f; \ |
((char *)&f)[3] = *((INPUT)); \ |
((char *)&f)[2] = *((INPUT)+1); \ |
((char *)&f)[1] = *((INPUT)+2); \ |
((char *)&f)[0] = *((INPUT)+3); \ |
(SVAL).u.float_number = f; \ |
} while(0) |
#else |
#define EXTRACT_FLOAT(SVAL, INPUT, SHIFT) \ |
/* FIXME! */ \ |
(SVAL).u.float_number = low_parse_IEEE_float((INPUT), 4) |
#endif |
#endif |
|
#ifdef DOUBLE_IS_IEEE_BIG |
#define EXTRACT_DOUBLE(SVAL, INPUT, SHIFT) \ |
do { \ |
double d; \ |
((char *)&d)[0] = *((INPUT)); \ |
((char *)&d)[1] = *((INPUT)+1); \ |
((char *)&d)[2] = *((INPUT)+2); \ |
((char *)&d)[3] = *((INPUT)+3); \ |
((char *)&d)[4] = *((INPUT)+4); \ |
((char *)&d)[5] = *((INPUT)+5); \ |
((char *)&d)[6] = *((INPUT)+6); \ |
((char *)&d)[7] = *((INPUT)+7); \ |
(SVAL).u.float_number = (float)d; \ |
} while(0) |
#else |
#ifdef DOUBLE_IS_IEEE_LITTLE |
#define EXTRACT_DOUBLE(SVAL, INPUT, SHIFT) \ |
do { \ |
double d; \ |
((char *)&d)[7] = *((INPUT)); \ |
((char *)&d)[6] = *((INPUT)+1); \ |
((char *)&d)[5] = *((INPUT)+2); \ |
((char *)&d)[4] = *((INPUT)+3); \ |
((char *)&d)[3] = *((INPUT)+4); \ |
((char *)&d)[2] = *((INPUT)+5); \ |
((char *)&d)[1] = *((INPUT)+6); \ |
((char *)&d)[0] = *((INPUT)+7); \ |
(SVAL).u.float_number = (float)d; \ |
} while(0) |
#else |
#define EXTRACT_DOUBLE(SVAL, INPUT, SHIFT) \ |
/* FIXME! */ \ |
(SVAL).u.float_number = low_parse_IEEE_float((INPUT), 8) |
#endif |
#endif |
|
#define MK_VERY_LOW_SSCANF(INPUT_SHIFT, MATCH_SHIFT) \ |
static INT32 PIKE_CONCAT4(very_low_sscanf_,INPUT_SHIFT,_,MATCH_SHIFT)( \ |
PIKE_CONCAT(p_wchar, INPUT_SHIFT) *input, \ |
long input_len, \ |
PIKE_CONCAT(p_wchar, MATCH_SHIFT) *match, \ |
long match_len, \ |
long *chars_matched, \ |
int *success) \ |
{ \ |
struct svalue sval; \ |
int e,cnt,matches,eye,arg; \ |
int no_assign = 0, field_length = 0, minus_flag = 0; \ |
char set[256]; \ |
struct svalue *argp; \ |
\ |
success[0]=0; \ |
\ |
arg=eye=matches=0; \ |
\ |
for(cnt = 0; cnt < match_len; cnt++) \ |
{ \ |
for(;cnt<match_len;cnt++) \ |
{ \ |
if(match[cnt]=='%') \ |
{ \ |
if(match[cnt+1]=='%') \ |
{ \ |
cnt++; \ |
}else{ \ |
break; \ |
} \ |
} \ |
if(eye>=input_len || input[eye]!=match[cnt]) \ |
{ \ |
chars_matched[0]=eye; \ |
return matches; \ |
} \ |
eye++; \ |
} \ |
if(cnt>=match_len) \ |
{ \ |
chars_matched[0]=eye; \ |
return matches; \ |
} \ |
\ |
DO_IF_DEBUG( \ |
if(match[cnt]!='%' || match[cnt+1]=='%') \ |
{ \ |
fatal("Error in sscanf.\n"); \ |
} \ |
); \ |
\ |
no_assign=0; \ |
field_length=-1; \ |
minus_flag=0; \ |
\ |
cnt++; \ |
if(cnt>=match_len) \ |
error("Error in sscanf format string.\n"); \ |
\ |
while(1) \ |
{ \ |
switch(match[cnt]) \ |
{ \ |
case '*': \ |
no_assign=1; \ |
cnt++; \ |
if(cnt>=match_len) \ |
error("Error in sscanf format string.\n"); \ |
continue; \ |
\ |
case '0': case '1': case '2': case '3': case '4': \ |
case '5': case '6': case '7': case '8': case '9': \ |
{ \ |
PCHARP t; \ |
field_length = STRTOL_PCHARP(MKPCHARP(match+cnt, MATCH_SHIFT),\ |
&t,10); \ |
cnt = SUBTRACT_PCHARP(t, MKPCHARP(match, MATCH_SHIFT)); \ |
continue; \ |
} \ |
\ |
case '-': \ |
minus_flag=1; \ |
cnt++; \ |
continue; \ |
\ |
case '{': \ |
{ \ |
ONERROR err; \ |
long tmp; \ |
for(e=cnt+1,tmp=1;tmp;e++) \ |
{ \ |
if(!match[e]) \ |
{ \ |
error("Missing %%} in format string.\n"); \ |
break; /* UNREACHED */ \ |
} \ |
if(match[e]=='%') \ |
{ \ |
switch(match[e+1]) \ |
{ \ |
case '%': e++; break; \ |
case '}': tmp--; break; \ |
case '{': tmp++; break; \ |
} \ |
} \ |
} \ |
sval.type=T_ARRAY; \ |
sval.u.array=allocate_array(0); \ |
SET_ONERROR(err, do_free_array, sval.u.array); \ |
\ |
while(input_len-eye) \ |
{ \ |
int yes; \ |
struct svalue *save_sp=sp; \ |
PIKE_CONCAT4(very_low_sscanf_, INPUT_SHIFT, _, MATCH_SHIFT)(\ |
input+eye, \ |
input_len-eye, \ |
match+cnt+1, \ |
e-cnt-2, \ |
&tmp, \ |
&yes); \ |
if(yes && tmp) \ |
{ \ |
f_aggregate(sp-save_sp); \ |
sval.u.array=append_array(sval.u.array,sp-1); \ |
pop_stack(); \ |
eye+=tmp; \ |
}else{ \ |
pop_n_elems(sp-save_sp); \ |
break; \ |
} \ |
} \ |
cnt=e; \ |
UNSET_ONERROR(err); \ |
break; \ |
} \ |
\ |
case 'c': \ |
if(field_length == -1) field_length = 1; \ |
if(eye+field_length > input_len) \ |
{ \ |
chars_matched[0]=eye; \ |
return matches; \ |
} \ |
sval.type=T_INT; \ |
sval.subtype=NUMBER_NUMBER; \ |
sval.u.integer=0; \ |
if (minus_flag) \ |
{ \ |
int x, pos=0; \ |
\ |
while(--field_length >= 0) \ |
{ \ |
int lshfun, orfun; \ |
x = input[eye]; \ |
\ |
DO_IF_BIGNUM( \ |
if(INT_TYPE_LSH_OVERFLOW(x, pos)) \ |
{ \ |
push_int(sval.u.integer); \ |
convert_stack_top_to_bignum(); \ |
lshfun=FIND_LFUN(sp[-1].u.object->prog, LFUN_LSH); \ |
orfun=FIND_LFUN(sp[-1].u.object->prog, LFUN_OR); \ |
\ |
while(field_length-- >= 0) \ |
{ \ |
push_int(input[eye]); \ |
convert_stack_top_to_bignum(); \ |
push_int(pos); \ |
apply_low(sp[-2].u.object, lshfun, 1); \ |
stack_swap(); \ |
pop_stack(); \ |
apply_low(sp[-2].u.object, orfun, 1); \ |
stack_swap(); \ |
pop_stack(); \ |
pos+=8; \ |
eye++; \ |
} \ |
sval=*--sp; \ |
break; \ |
} \ |
); \ |
sval.u.integer|=x<<pos; \ |
\ |
pos+=8; \ |
eye++; \ |
} \ |
} \ |
else \ |
while(--field_length >= 0) \ |
{ \ |
int lshfun, orfun; \ |
DO_IF_BIGNUM( \ |
if(INT_TYPE_LSH_OVERFLOW(sval.u.integer, 8)) \ |
{ \ |
push_int(sval.u.integer); \ |
convert_stack_top_to_bignum(); \ |
lshfun=FIND_LFUN(sp[-1].u.object->prog, LFUN_LSH); \ |
orfun=FIND_LFUN(sp[-1].u.object->prog, LFUN_OR); \ |
\ |
while(field_length-- >= 0) \ |
{ \ |
push_int(8); \ |
apply_low(sp[-2].u.object, lshfun, 1); \ |
stack_swap(); \ |
pop_stack(); \ |
push_int(input[eye]); \ |
apply_low(sp[-2].u.object, orfun, 1); \ |
stack_swap(); \ |
pop_stack(); \ |
eye++; \ |
} \ |
sval=*--sp; \ |
break; \ |
} \ |
); \ |
sval.u.integer<<=8; \ |
sval.u.integer |= input[eye]; \ |
eye++; \ |
} \ |
break; \ |
\ |
case 'b': \ |
case 'o': \ |
case 'd': \ |
case 'x': \ |
case 'D': \ |
case 'i': \ |
{ \ |
int base = 0; \ |
PIKE_CONCAT(p_wchar, INPUT_SHIFT) *t; \ |
\ |
if(eye>=input_len) \ |
{ \ |
chars_matched[0]=eye; \ |
return matches; \ |
} \ |
\ |
switch(match[cnt]) \ |
{ \ |
case 'b': base = 2; break; \ |
case 'o': base = 8; break; \ |
case 'd': base = 10; break; \ |
case 'x': base = 16; break; \ |
} \ |
\ |
wide_string_to_svalue_inumber(&sval, input+eye, (void **)&t, \ |
base, field_length, \ |
INPUT_SHIFT); \ |
\ |
if(input + eye == t) \ |
{ \ |
chars_matched[0]=eye; \ |
return matches; \ |
} \ |
eye=t-input; \ |
break; \ |
} \ |
\ |
case 'f': \ |
{ \ |
PIKE_CONCAT(p_wchar, INPUT_SHIFT) *t; \ |
PCHARP t2; \ |
\ |
if(eye>=input_len) \ |
{ \ |
chars_matched[0]=eye; \ |
return matches; \ |
} \ |
sval.u.float_number=STRTOD_PCHARP(MKPCHARP(input+eye, \ |
INPUT_SHIFT),&t2); \ |
t = (PIKE_CONCAT(p_wchar, INPUT_SHIFT) *)(t2.ptr); \ |
if(input + eye == t) \ |
{ \ |
chars_matched[0]=eye; \ |
return matches; \ |
} \ |
eye=t-input; \ |
sval.type=T_FLOAT; \ |
DO_IF_CHECKER(sval.subtype=0); \ |
break; \ |
} \ |
\ |
case 'F': \ |
if(field_length == -1) field_length = 4; \ |
if(field_length != 4 && field_length != 8) \ |
error("Invalid IEEE width %d in sscanf format string.\n", \ |
field_length); \ |
if(eye+field_length > input_len) \ |
{ \ |
chars_matched[0]=eye; \ |
return matches; \ |
} \ |
sval.type=T_FLOAT; \ |
DO_IF_CHECKER(sval.subtype=0); \ |
switch(field_length) { \ |
case 4: \ |
EXTRACT_FLOAT(sval, input+eye, INPUT_SHIFT); \ |
eye += 4; \ |
break; \ |
case 8: \ |
EXTRACT_DOUBLE(sval, input+eye, INPUT_SHIFT); \ |
eye += 8; \ |
break; \ |
} \ |
break; \ |
\ |
case 's': \ |
if(field_length != -1) \ |
{ \ |
if(input_len - eye < field_length) \ |
{ \ |
chars_matched[0]=eye; \ |
return matches; \ |
} \ |
\ |
sval.type=T_STRING; \ |
DO_IF_CHECKER(sval.subtype=0); \ |
sval.u.string=PIKE_CONCAT(make_shared_binary_string, \ |
INPUT_SHIFT)(input+eye, \ |
field_length); \ |
eye+=field_length; \ |
break; \ |
} \ |
\ |
if(cnt+1>=match_len) \ |
{ \ |
sval.type=T_STRING; \ |
DO_IF_CHECKER(sval.subtype=0); \ |
sval.u.string=PIKE_CONCAT(make_shared_binary_string, \ |
INPUT_SHIFT)(input+eye, \ |
input_len-eye); \ |
eye=input_len; \ |
break; \ |
}else{ \ |
PIKE_CONCAT(p_wchar, MATCH_SHIFT) *end_str_start; \ |
PIKE_CONCAT(p_wchar, MATCH_SHIFT) *end_str_end; \ |
PIKE_CONCAT(p_wchar, MATCH_SHIFT) *s=0; \ |
PIKE_CONCAT(p_wchar, MATCH_SHIFT) *p=0; \ |
int start,contains_percent_percent, new_eye; \ |
\ |
start=eye; \ |
end_str_start=match+cnt+1; \ |
\ |
s=match+cnt+1; \ |
test_again: \ |
if(*s=='%') \ |
{ \ |
s++; \ |
if(*s=='*') s++; \ |
switch(*s) \ |
{ \ |
case 'n': \ |
s++; \ |
goto test_again; \ |
\ |
case 's': \ |
error("Illegal to have two adjecent %%s.\n"); \ |
return 0; /* make gcc happy */ \ |
\ |
/* sscanf("foo-bar","%s%d",a,b) might not work as expected */ \ |
case 'd': \ |
for(e=0;e<256;e++) set[e]=1; \ |
for(e='0';e<='9';e++) set[e]=0; \ |
set['-']=0; \ |
goto match_set; \ |
\ |
case 'o': \ |
for(e=0;e<256;e++) set[e]=1; \ |
for(e='0';e<='7';e++) set[e]=0; \ |
goto match_set; \ |
\ |
case 'x': \ |
for(e=0;e<256;e++) set[e]=1; \ |
for(e='0';e<='9';e++) set[e]=0; \ |
for(e='a';e<='f';e++) set[e]=0; \ |
goto match_set; \ |
\ |
case 'D': \ |
for(e=0;e<256;e++) set[e]=1; \ |
for(e='0';e<='9';e++) set[e]=0; \ |
set['-']=0; \ |
set['x']=0; \ |
goto match_set; \ |
\ |
case 'f': \ |
for(e=0;e<256;e++) set[e]=1; \ |
for(e='0';e<='9';e++) set[e]=0; \ |
set['.']=set['-']=0; \ |
goto match_set; \ |
\ |
case '[': /* oh dear */ \ |
/* FIXME! */ \ |
read_set(match,s-match+1,set,match_len); \ |
for(e=0;e<256;e++) set[e]=!set[e]; \ |
goto match_set; \ |
} \ |
} \ |
\ |
contains_percent_percent=0; \ |
\ |
for(e=cnt;e<match_len;e++) \ |
{ \ |
if(match[e]=='%') \ |
{ \ |
if(match[e+1]=='%') \ |
{ \ |
contains_percent_percent=1; \ |
e++; \ |
}else{ \ |
break; \ |
} \ |
} \ |
} \ |
\ |
end_str_end=match+e; \ |
\ |
if(!contains_percent_percent) \ |
{ \ |
struct generic_mem_searcher searcher; \ |
PIKE_CONCAT(p_wchar, INPUT_SHIFT) *s2; \ |
init_generic_memsearcher(&searcher, end_str_start, \ |
end_str_end - end_str_start, \ |
MATCH_SHIFT, input_len - eye, \ |
INPUT_SHIFT); \ |
s2 = generic_memory_search(&searcher, input+eye, \ |
input_len - eye, INPUT_SHIFT); \ |
if(!s2) \ |
{ \ |
chars_matched[0]=eye; \ |
return matches; \ |
} \ |
eye=s2-input; \ |
new_eye=eye+end_str_end-end_str_start; \ |
}else{ \ |
PIKE_CONCAT(p_wchar, INPUT_SHIFT) *p2 = NULL; \ |
for(;eye<input_len;eye++) \ |
{ \ |
p2=input+eye; \ |
for(s=end_str_start;s<end_str_end;s++,p2++) \ |
{ \ |
if(*s!=*p2) break; \ |
if(*s=='%') s++; \ |
} \ |
if(s==end_str_end) \ |
break; \ |
} \ |
if(eye==input_len) \ |
{ \ |
chars_matched[0]=eye; \ |
return matches; \ |
} \ |
new_eye=p2-input; \ |
} \ |
\ |
sval.type=T_STRING; \ |
DO_IF_CHECKER(sval.subtype=0); \ |
sval.u.string=PIKE_CONCAT(make_shared_binary_string, \ |
INPUT_SHIFT)(input+start, \ |
eye-start); \ |
\ |
cnt=end_str_end-match-1; \ |
eye=new_eye; \ |
break; \ |
} \ |
\ |
case '[': \ |
/* FIXME! */ \ |
cnt=read_set(match,cnt+1,set,match_len); \ |
\ |
match_set: \ |
/* FIXME! */ \ |
for(e=eye;eye<input_len && !(input[eye]&~0xff) && \ |
set[input[eye]];eye++); \ |
sval.type=T_STRING; \ |
DO_IF_CHECKER(sval.subtype=0); \ |
sval.u.string=PIKE_CONCAT(make_shared_binary_string, \ |
INPUT_SHIFT)(input+e,eye-e); \ |
break; \ |
\ |
case 'n': \ |
sval.type=T_INT; \ |
sval.subtype=NUMBER_NUMBER; \ |
sval.u.integer=eye; \ |
break; \ |
\ |
default: \ |
error("Unknown sscanf token %%%c(0x%02x)\n", \ |
match[cnt], match[cnt]); \ |
} \ |
break; \ |
} \ |
matches++; \ |
\ |
if(no_assign) \ |
{ \ |
free_svalue(&sval); \ |
}else{ \ |
check_stack(1); \ |
*sp++=sval; \ |
DO_IF_DEBUG(sval.type=99); \ |
} \ |
} \ |
chars_matched[0]=eye; \ |
success[0]=1; \ |
return matches; \ |
} |
|
MK_VERY_LOW_SSCANF(0,0) |
MK_VERY_LOW_SSCANF(0,1) |
MK_VERY_LOW_SSCANF(0,2) |
MK_VERY_LOW_SSCANF(1,0) |
MK_VERY_LOW_SSCANF(1,1) |
MK_VERY_LOW_SSCANF(1,2) |
MK_VERY_LOW_SSCANF(2,0) |
MK_VERY_LOW_SSCANF(2,1) |
MK_VERY_LOW_SSCANF(2,2) |
|
void o_sscanf(INT32 args) |
{ |
#ifdef PIKE_DEBUG |
extern int t_flag; |
#endif |
INT32 e,i; |
int x; |
long matched_chars; |
struct svalue *save_sp=sp; |
|
if(sp[-args].type != T_STRING) |
error("Bad argument 1 to sscanf().\n"); |
|
if(sp[1-args].type != T_STRING) |
error("Bad argument 1 to sscanf().\n"); |
|
switch(sp[-args].u.string->size_shift*3 + sp[1-args].u.string->size_shift) { |
|
case 0: |
|
i=very_low_sscanf_0_0(STR0(sp[-args].u.string), |
sp[-args].u.string->len, |
STR0(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 1: |
|
i=very_low_sscanf_0_1(STR0(sp[-args].u.string), |
sp[-args].u.string->len, |
STR1(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 2: |
|
i=very_low_sscanf_0_2(STR0(sp[-args].u.string), |
sp[-args].u.string->len, |
STR2(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 3: |
|
i=very_low_sscanf_1_0(STR1(sp[-args].u.string), |
sp[-args].u.string->len, |
STR0(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 4: |
|
i=very_low_sscanf_1_1(STR1(sp[-args].u.string), |
sp[-args].u.string->len, |
STR1(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 5: |
|
i=very_low_sscanf_1_2(STR1(sp[-args].u.string), |
sp[-args].u.string->len, |
STR2(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 6: |
|
i=very_low_sscanf_2_0(STR2(sp[-args].u.string), |
sp[-args].u.string->len, |
STR0(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 7: |
|
i=very_low_sscanf_2_1(STR2(sp[-args].u.string), |
sp[-args].u.string->len, |
STR1(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 8: |
|
i=very_low_sscanf_2_2(STR2(sp[-args].u.string), |
sp[-args].u.string->len, |
STR2(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
default: |
error("Unsupported shift-combination to sscanf(): %d:%d\n", |
sp[-args].u.string->size_shift, sp[1-args].u.string->size_shift); |
break; |
} |
|
if(sp-save_sp > args/2-1) |
error("Too few arguments for sscanf format.\n"); |
|
for(x=0;x<sp-save_sp;x++) |
assign_lvalue(save_sp-args+2+x*2,save_sp+x); |
pop_n_elems(sp-save_sp +args); |
|
#ifdef PIKE_DEBUG |
if(t_flag >2) |
{ |
int nonblock; |
if((nonblock=query_nonblocking(2))) |
set_nonblocking(2,0); |
|
fprintf(stderr,"- Matches: %ld\n",(long)i); |
if(nonblock) |
set_nonblocking(2,1); |
} |
#endif |
push_int(i); |
} |
|
void f_sscanf(INT32 args) |
{ |
#ifdef PIKE_DEBUG |
extern int t_flag; |
#endif |
INT32 e,i; |
int x; |
long matched_chars; |
struct svalue *save_sp=sp; |
struct array *a; |
|
check_all_args("array_sscanf",args,BIT_STRING, BIT_STRING,0); |
|
switch(sp[-args].u.string->size_shift*3 + sp[1-args].u.string->size_shift) { |
|
case 0: |
|
i=very_low_sscanf_0_0(STR0(sp[-args].u.string), |
sp[-args].u.string->len, |
STR0(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 1: |
|
i=very_low_sscanf_0_1(STR0(sp[-args].u.string), |
sp[-args].u.string->len, |
STR1(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 2: |
|
i=very_low_sscanf_0_2(STR0(sp[-args].u.string), |
sp[-args].u.string->len, |
STR2(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 3: |
|
i=very_low_sscanf_1_0(STR1(sp[-args].u.string), |
sp[-args].u.string->len, |
STR0(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 4: |
|
i=very_low_sscanf_1_1(STR1(sp[-args].u.string), |
sp[-args].u.string->len, |
STR1(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 5: |
|
i=very_low_sscanf_1_2(STR1(sp[-args].u.string), |
sp[-args].u.string->len, |
STR2(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 6: |
|
i=very_low_sscanf_2_0(STR2(sp[-args].u.string), |
sp[-args].u.string->len, |
STR0(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 7: |
|
i=very_low_sscanf_2_1(STR2(sp[-args].u.string), |
sp[-args].u.string->len, |
STR1(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
case 8: |
|
i=very_low_sscanf_2_2(STR2(sp[-args].u.string), |
sp[-args].u.string->len, |
STR2(sp[1-args].u.string), |
sp[1-args].u.string->len, |
&matched_chars, |
&x); |
break; |
default: |
error("Unsupported shift-combination to sscanf(): %d:%d\n", |
sp[-args].u.string->size_shift, sp[1-args].u.string->size_shift); |
break; |
} |
|
a=aggregate_array(sp-save_sp); |
pop_n_elems(args); |
push_array(a); |
} |
|
|
|