Skip to content
Snippets Groups Projects
Select Git revision
  • d6d348fb78ce80c85370afde6ae320ed68e65807
  • master default protected
  • 9.0
  • 8.0
  • 7.8
  • 7.6
  • 7.4
  • 7.2
  • 7.0
  • 0.6
  • rosuav/latex-markdown-renderer
  • rxnpatch/rxnpatch
  • marcus/gobject-introspection
  • rxnpatch/8.0
  • rosuav/pre-listening-ports
  • nt-tools
  • rosuav/async-annotations
  • rosuav/pgsql-ssl
  • rxnpatch/rxnpatch-broken/2023-10-06T094250
  • grubba/fdlib
  • grubba/wip/sakura/8.0
  • v8.0.2000
  • v8.0.1998
  • v8.0.1996
  • v8.0.1994
  • v8.0.1992
  • v8.0.1990
  • v8.0.1988
  • v8.0.1986
  • rxnpatch/clusters/8.0/2025-04-29T124414
  • rxnpatch/2025-04-29T124414
  • v8.0.1984
  • v8.0.1982
  • v8.0.1980
  • v8.0.1978
  • v8.0.1976
  • v8.0.1974
  • v8.0.1972
  • v8.0.1970
  • v8.0.1968
  • v8.0.1966
41 results

backend.c

Blame
    • Fredrik Hübinette (Hubbe)'s avatar
      57408873
      lots of updates for NT, threads and new cpp · 57408873
      Fredrik Hübinette (Hubbe) authored
      Rev: src/ChangeLog:1.128
      Rev: src/Makefile.in:1.49
      Rev: src/backend.c:1.20
      Rev: src/configure.in:1.145
      Rev: src/cpp.c:1.2
      Rev: src/cpp.h:1.2
      Rev: src/fd_control.c:1.11
      Rev: src/fdlib.c:1.1
      Rev: src/fdlib.h:1.1
      Rev: src/fsort.c:1.3
      Rev: src/fsort_template.h:1.2
      Rev: src/lex.c:1.36
      Rev: src/lex.h:1.6
      Rev: src/main.c:1.29
      Rev: src/modules/files/file.c:1.63
      Rev: src/modules/files/socket.c:1.20
      Rev: src/modules/readline/readlinemod.c:1.4
      Rev: src/object.c:1.30
      Rev: src/object.h:1.12
      Rev: src/port.c:1.13
      Rev: src/program.c:1.47
      Rev: src/program.h:1.23
      Rev: src/stuff.c:1.4
      Rev: src/stuff.h:1.4
      Rev: src/threads.c:1.48
      Rev: src/threads.h:1.22
      Rev: src/time_stuff.h:1.5
      57408873
      History
      lots of updates for NT, threads and new cpp
      Fredrik Hübinette (Hubbe) authored
      Rev: src/ChangeLog:1.128
      Rev: src/Makefile.in:1.49
      Rev: src/backend.c:1.20
      Rev: src/configure.in:1.145
      Rev: src/cpp.c:1.2
      Rev: src/cpp.h:1.2
      Rev: src/fd_control.c:1.11
      Rev: src/fdlib.c:1.1
      Rev: src/fdlib.h:1.1
      Rev: src/fsort.c:1.3
      Rev: src/fsort_template.h:1.2
      Rev: src/lex.c:1.36
      Rev: src/lex.h:1.6
      Rev: src/main.c:1.29
      Rev: src/modules/files/file.c:1.63
      Rev: src/modules/files/socket.c:1.20
      Rev: src/modules/readline/readlinemod.c:1.4
      Rev: src/object.c:1.30
      Rev: src/object.h:1.12
      Rev: src/port.c:1.13
      Rev: src/program.c:1.47
      Rev: src/program.h:1.23
      Rev: src/stuff.c:1.4
      Rev: src/stuff.h:1.4
      Rev: src/threads.c:1.48
      Rev: src/threads.h:1.22
      Rev: src/time_stuff.h:1.5
    opcodes.c 41.87 KiB
    /*\
    ||| This file a part of Pike, and is copyright by Fredrik Hubinette
    ||| Pike is distributed as GPL (General Public License)
    ||| See the files COPYING and DISCLAIMER for more information.
    \*/
    /**/
    #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"
    #include "operators.h"
    
    RCSID("$Id: opcodes.c,v 1.84 2000/08/13 19:34:34 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:
        {
          INT_TYPE val = what->u.integer;
    
          convert_svalue_to_bignum(what);
          index_no_free(to, what, ind);
          if(IS_UNDEFINED(to)) {
    	if (val) {
    	  error("Indexing the integer %d with an unknown method.\n", val);
    	} else {
    	  error("Indexing the NULL value.\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;
          }
        }
        /* FALL THROUGH */
    
      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_MULTISET:
    	switch(sp[-1].type)
    	{
    	  case T_ARRAY:
    	  {
    	    extern void f_mkmultiset(INT32);
    	    f_mkmultiset(1);
    	    break;
    	  }
    
    	  default:
    	    error("Cannot cast %s to multiset.\n",get_name_of_type(sp[-1].type));
    	}
    	break;
    	
          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)))
    	    {
    	      /* Note: This includes the case when i = 0x80000000, i.e.
    		 the absolute value is not computable. */
    	      convert_stack_top_to_bignum();
    	      return;   /* FIXME: OK to return? Cast tests below indicates
    			   we have to do this, at least for now... /Noring */
    	      /* Yes, it is ok to return, it is actually an optimization :)
    	       * /Hubbe
    	       */
    	    }
    	    else
    #endif /* AUTO_BIGNUM */
    	    {
    	      sp[-1].type=T_INT;
    	      sp[-1].u.integer=i;
    	    }
    	    break;
    	    
    	  case T_STRING:
    	    /* This can be here independently of AUTO_BIGNUM. Besides,
    	       we really want to reduce the number of number parsers
    	       around here. :) /Noring */
    #ifdef AUTO_BIGNUM
    	    convert_stack_top_string_to_inumber(10);
    	    return;   /* FIXME: OK to return? Cast tests below indicates
    			 we have to do this, at least for now... /Noring */
    	      /* Yes, it is ok to return, it is actually an optimization :)
    	       * /Hubbe
    	       */
    #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_PCHARP(MKPCHARP(sp[-1].u.string->str,
    				     sp[-1].u.string->size_shift),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(Pike_fp->pc)
    	    {
    	      INT32 lineno;
    	      push_text(get_line(Pike_fp->pc, Pike_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(Pike_fp->pc)
    	  {
    	    INT32 lineno;
    	    push_text(get_line(Pike_fp->pc, Pike_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,int_type_string,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,mixed_type_string,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(m_sizeof(tmp)));
    	  
    	  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);
        }
      }
    }
    
    
    PMOD_EXPORT 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);
    }
    
    
    /*
      flags:
       *
      operators:
      %d
      %s
      %f
      %c
      %n
      %[
      %%
    */
    
    
    struct sscanf_set
    {
      int neg;
      char c[256];
      struct array *a;
    };
    
    /* FIXME:
     * This implementation will break in certain cases, especially cases
     * like this [\1000-\1002\1001] (ie, there is a single character which
     * is also a part of a range
     *   /Hubbe
     */
    
    
    #define MKREADSET(SIZE)						\
    static int PIKE_CONCAT(read_set,SIZE) (				\
      PIKE_CONCAT(p_wchar,SIZE) *match,				\
      int cnt,							\
      struct sscanf_set *set,					\
      int match_len)						\
    {								\
      unsigned long e,last=0;					\
      CHAROPT( int set_size=0; )					\
    								\
      if(cnt>=match_len)						\
        error("Error in sscanf format string.\n");			\
    								\
      MEMSET(set->c, 0, sizeof(set->c));				\
      set->a=0;							\
    								\
      if(match[cnt]=='^')						\
      {								\
        set->neg=1;							\
        cnt++;							\
        if(cnt>=match_len)						\
          error("Error in sscanf format string.\n");		\
      }else{							\
        set->neg=0;							\
      }								\
    								\
      if(match[cnt]==']' || match[cnt]=='-')			\
      {								\
        set->c[last=match[cnt]]=1;					\
        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->c['-']=1;						\
    	break;							\
          }								\
    								\
          if(last >= match[cnt])					\
    	error("Error in sscanf format string.\n");		\
    								\
    CHAROPT(							\
          if(last < (unsigned long)sizeof(set->c))			\
          {								\
    	if(match[cnt] < (unsigned long)sizeof(set->c))		\
    	{							\
    )								\
    	  for(e=last;e<=match[cnt];e++) set->c[e]=1;		\
    CHAROPT(							\
    	}else{							\
    	  for(e=last;e<(unsigned long)sizeof(set->c);e++)	\
                set->c[e]=1;					\
    								\
    	  check_stack(2);					\
    	  push_int(256);					\
    	  push_int(match[cnt]);					\
    	  set_size++;						\
    	}							\
          }								\
          else							\
          {								\
    	sp[-1].u.integer=match[cnt];				\
          }								\
    )								\
          continue;							\
        }								\
        last=match[cnt];						\
        if(last < (unsigned long)sizeof(set->c))			\
          set->c[last]=1;						\
    CHAROPT(							\
        else{							\
          if(set_size &&						\
    	 ((unsigned long)sp[-1].u.integer) == last-1)		\
          {								\
    	sp[-1].u.integer++;					\
          }else{							\
    	check_stack(2);						\
    	push_int(last);						\
    	push_int(last);						\
    	set_size++;						\
          }								\
        }								\
    )								\
      }								\
    								\
    CHAROPT(							\
      if(set_size)							\
      {								\
        INT32 *order;						\
        set->a=aggregate_array(set_size*2);				\
        order=get_switch_order(set->a);				\
        for(e=0;e<(unsigned long)set->a->size;e+=2)			\
        {								\
          if(order[e]+1 != order[e+1])				\
          {								\
            free_array(set->a);					\
            set->a=0;						\
            free((char *)order);					\
            error("Overlapping ranges in sscanf not supported.\n");	\
          }								\
        }								\
    								\
        order_array(set->a,order);					\
        free((char *)order);					\
      }								\
    )								\
      return cnt;							\
    }
    
    
    
    /* Parse binary IEEE strings on a machine which uses a different kind
       of floating point internally */
    
    #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); /* defined in encode.c */
    #endif
    
    static INLINE FLOAT_TYPE 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) {
          /* NAN */
          
          /* Hmm...  No idea how to generate NaN in a portable way. */
          /* Let's turn it into a 0 for now... */
          return (FLOAT_TYPE)0.0;
        } else {
          /* +/- Infinity */
    #ifdef HUGE_VAL
          return (FLOAT_TYPE)(s? -HUGE_VAL:HUGE_VAL);
    #else
          /* This number is infinite enough...  :) */
          e = 1024;
          f = 1;
          extra_f = 0;
    #endif
        }
    
      r = (double)f;
      if(extra_f)
        r += ((double)extra_f)/4294967296.0;
      return (FLOAT_TYPE)(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)				\
    	    do {							\
    	      char x[4];						\
    	      x[0] = (INPUT)[0];					\
    	      x[1] = (INPUT)[1];					\
    	      x[2] = (INPUT)[2];					\
    	      x[3] = (INPUT)[3];					\
    	      (SVAL).u.float_number = low_parse_IEEE_float(x, 4);	\
                } while(0)
    #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)				\
    	    do {							\
    	      char x[8];						\
    	      x[0] = (INPUT)[0];					\
    	      x[1] = (INPUT)[1];					\
    	      x[2] = (INPUT)[2];					\
    	      x[3] = (INPUT)[3];					\
    	      x[4] = (INPUT)[4];					\
    	      x[5] = (INPUT)[5];					\
    	      x[6] = (INPUT)[6];					\
    	      x[7] = (INPUT)[7];					\
    	      (SVAL).u.float_number = low_parse_IEEE_float(x, 8);	\
    	    } while(0)
    #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,	 \
    			 ptrdiff_t input_len,				 \
    			 PIKE_CONCAT(p_wchar, MATCH_SHIFT) *match,	 \
    			 ptrdiff_t match_len,				 \
    			 ptrdiff_t *chars_matched,			 \
    			 int *success)					 \
    {									 \
      struct svalue sval;							 \
      INT32 matches, arg;							 \
      ptrdiff_t cnt, eye, e;						 \
      int no_assign = 0, field_length = 0, minus_flag = 0;			 \
      struct sscanf_set set;						 \
      struct svalue *argp;							 \
    									 \
    									 \
      set.a = 0;								 \
      success[0] = 0;							 \
    									 \
      eye = arg = 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;							 \
    	  ptrdiff_t tmp;						 \
    	  for(e=cnt+1,tmp=1;tmp;e++)					 \
    	  {								 \
    	    if(e>=match_len)						 \
    	    {								 \
    	      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':							 \
            {								 \
              int e;							 \
    	  sval.type=T_INT;						 \
    	  sval.subtype=NUMBER_NUMBER;					 \
              if(field_length == -1)					 \
              { 								 \
    	    if(eye+1 > input_len)					 \
    	    {								 \
    	      chars_matched[0]=eye;					 \
    	      return matches;						 \
    	    }								 \
                sval.u.integer=input[eye];					 \
    	    eye++;							 \
                break;							 \
              }								 \
    	  if(eye+field_length > input_len)				 \
    	  {								 \
    	    chars_matched[0]=eye;					 \
    	    return matches;						 \
    	  }								 \
    CHAROPT2(								 \
              for(e=0;e<field_length;e++)					 \
              {								 \
                 if(input[eye+e]>255)					 \
                 {								 \
                   chars_matched[0]=eye;					 \
                   return matches;						 \
                 }								 \
              }								 \
    )									 \
    	  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();				 \
    									 \
    		 while(field_length-- >= 0)				 \
    		 {							 \
    		   push_int(input[eye]);				 \
    		   convert_stack_top_to_bignum();			 \
    		   push_int(pos);					 \
    		   o_lsh();						 \
    		   o_or();						 \
    		   pos+=8;						 \
    		   eye++;						 \
    		 }							 \
    		 sval=*--sp;						 \
    		 break;							 \
    	       }							 \
                   );							 \
    	       sval.u.integer|=x<<pos;					 \
    									 \
    	       pos+=8;							 \
    	       eye++;							 \
    	     }								 \
    	  }								 \
    	  else								 \
    	     while(--field_length >= 0)					 \
    	     {								 \
                   DO_IF_BIGNUM(						 \
    	       if(INT_TYPE_LSH_OVERFLOW(sval.u.integer, 8))		 \
    	       {							 \
    		 push_int(sval.u.integer);				 \
    		 convert_stack_top_to_bignum();				 \
    									 \
    		 while(field_length-- >= 0)				 \
    		 {							 \
    		   push_int(8);						 \
    		   o_lsh();						 \
    		   push_int(input[eye]);				 \
    		   o_or();						 \
    		   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 contains_percent_percent;				 \
                ptrdiff_t start, new_eye;					 \
    									 \
    	    start=eye;							 \
    	    end_str_start=match+cnt+1;					 \
    									 \
    	    s=match+cnt+1;						 \
          test_again:							 \
    	    if(*s=='%')							 \
    	    {								 \
    	      s++;							 \
    	      if(*s=='*') s++;						 \
                  set.neg=0;						 \
    	      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':						 \
    		  MEMSET(set.c, 1, sizeof(set.c));			 \
    		  for(e='0';e<='9';e++) set.c[e]=0;			 \
    		  set.c['-']=0;						 \
    		  goto match_set;					 \
    									 \
    		case 'o':						 \
    		  MEMSET(set.c, 1, sizeof(set.c));			 \
    		  for(e='0';e<='7';e++) set.c[e]=0;			 \
    		  goto match_set;					 \
    									 \
    		case 'x':						 \
    		  MEMSET(set.c, 1, sizeof(set.c));			 \
    		  for(e='0';e<='9';e++) set.c[e]=0;			 \
    		  for(e='a';e<='f';e++) set.c[e]=0;			 \
    		  goto match_set;					 \
    									 \
    		case 'D':						 \
    		  MEMSET(set.c, 1, sizeof(set.c));			 \
    		  for(e='0';e<='9';e++) set.c[e]=0;			 \
    		  set.c['-']=0;						 \
    		  set.c['x']=0;						 \
    		  goto match_set;					 \
    									 \
    		case 'f':						 \
    		  MEMSET(set.c, 1, sizeof(set.c));			 \
    		  for(e='0';e<='9';e++) set.c[e]=0;			 \
    		  set.c['.']=set.c['-']=0;				 \
    		  goto match_set;					 \
    									 \
    		case '[':		/* oh dear */			 \
    		  PIKE_CONCAT(read_set,MATCH_SHIFT)(match,		 \
    						    s-match+1,		 \
    						    &set,		 \
    						    match_len);		 \
    		  set.neg=!set.neg;					 \
    		  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 '[':							 \
    	  cnt=PIKE_CONCAT(read_set,MATCH_SHIFT)(match,cnt+1,		 \
    						&set,match_len);	 \
    									 \
      match_set:								 \
    	  for(e=eye;eye<input_len;eye++)				 \
    	  {								 \
    CHAROPT2(								 \
    	    if(input[eye]<sizeof(set.c))				 \
    	    {								 \
    )									 \
    	      if(set.c[input[eye]] == set.neg)				 \
    		break;							 \
    CHAROPT2(								 \
    	    }else{							 \
    	      if(set.a)							 \
    	      {								 \
    		INT32 x;						 \
    		struct svalue tmp;					 \
    		tmp.type=T_INT;						 \
    		tmp.u.integer=input[eye];				 \
    		x=switch_lookup(set.a, &tmp);				 \
    		if( set.neg != (x<0 && (x&1)) ) break;			 \
    	      }else{							 \
    		break;							 \
    	      }								 \
    	    }								 \
    )									 \
    	  }								 \
              if(set.a) { free_array(set.a); set.a=0; }			 \
    	  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;							 \
    }
    
    
    /* Confusing? Yes - Hubbe */
    
    /* CHAROPT(X) is X if the match set is wide.
     * CHAROPT2(X) is X if the input is wide.
     */
    #define CHAROPT(X)
    #define CHAROPT2(X)
    
    MKREADSET(0)
    MK_VERY_LOW_SSCANF(0,0)
    
    #undef CHAROPT2
    #define CHAROPT2(X) X
    
    MK_VERY_LOW_SSCANF(1,0)
    MK_VERY_LOW_SSCANF(2,0)
    
    #undef CHAROPT
    #define CHAROPT(X) X
    
    MKREADSET(1)
    MKREADSET(2)
    
    #undef CHAROPT2
    #define CHAROPT2(X)
    
    MK_VERY_LOW_SSCANF(0,1)
    MK_VERY_LOW_SSCANF(0,2)
    
    #undef CHAROPT2
    #define CHAROPT2(X) X
    
    MK_VERY_LOW_SSCANF(1,1)
    MK_VERY_LOW_SSCANF(2,1)
    MK_VERY_LOW_SSCANF(1,2)
    MK_VERY_LOW_SSCANF(2,2)
    
    void o_sscanf(INT32 args)
    {
    #ifdef PIKE_DEBUG
      extern int t_flag;
    #endif
      INT32 e,i;
      int x;
      ptrdiff_t 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) {
        /* input_shift : match_shift */
      case 0:
        /*      0      :      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:
        /*      0      :      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:
        /*      0      :      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:
        /*      1      :      0 */
        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:
        /*      1      :      1 */
        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:
        /*      1      :      2 */
        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:
        /*      2      :      0 */
        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:
        /*      2      :      1 */
        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:
        /*      2      :      2 */
        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);
    }
    
    PMOD_EXPORT void f_sscanf(INT32 args)
    {
    #ifdef PIKE_DEBUG
      extern int t_flag;
    #endif
      INT32 e,i;
      int x;
      ptrdiff_t 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) {
        /* input_shift : match_shift */
      case 0:
        /*      0      :      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:
        /*      0      :      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:
        /*      0      :      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:
        /*      1      :      0 */
        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:
        /*      1      :      1 */
        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:
        /*      1      :      2 */
        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:
        /*      2      :      0 */
        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:
        /*      2      :      1 */
        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:
        /*      2      :      2 */
        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(DO_NOT_WARN(sp - save_sp));
      pop_n_elems(args);
      push_array(a);
    }