c6c01a2003-11-14Martin Stjernholm /* || This file is part of Pike. For copyright information see COPYRIGHT. || Pike is distributed under GPL, LGPL and MPL. See the file COPYING || for more information. */ #include "global.h" #include "interpret.h" #include "array.h"
38392e2015-09-06Per Hedbor #include "mapping.h" #include "multiset.h"
c6c01a2003-11-14Martin Stjernholm #include "stralloc.h" #include "pike_error.h" #include "fd_control.h" #include "builtin_functions.h" #include "module_support.h" #include "operators.h"
0ba1be2004-03-06Martin Nilsson #include "bignum.h"
f36a622017-02-09Henrik Grubbström (Grubba) #include "pike_compiler.h"
b0ca932004-06-01Martin Nilsson #include "pike_float.h"
6f16cb2008-05-18Henrik Grubbström (Grubba) #include "pike_types.h"
37e4132008-05-17Marcus Comstedt #include "sscanf.h"
a2133d2014-04-17Arne Goedeke #include "bitvector.h"
e0ac352018-01-18Martin Nilsson #include "pike_search.h"
c6c01a2003-11-14Martin Stjernholm 
e4e5a32004-09-18Martin Nilsson /*
c6c01a2003-11-14Martin Stjernholm  * helper functions for sscanf %O */ /* Calling convention:
38392e2015-09-06Per Hedbor  * res: svalue to fill in.
c6c01a2003-11-14Martin Stjernholm  * str: string to parse. * len: length of the string. * * Returns: * NULL on failure. * continuation point in str on success. */
38392e2015-09-06Per Hedbor  #define CONSUME(X) do{if(*len>=X){INC_PCHARP(*str,X);*len-=X;}}while(0) static p_wchar2 next_char( PCHARP *str, ptrdiff_t *len )
c6c01a2003-11-14Martin Stjernholm {
38392e2015-09-06Per Hedbor  p_wchar2 res = *len ? EXTRACT_PCHARP(*str) : 0; CONSUME(1); return res; } #define READ() next_char(str,len)
c6c01a2003-11-14Martin Stjernholm 
d0233c2018-07-05Henrik Grubbström (Grubba) #ifdef HANDLES_UNALIGNED_MEMORY_ACCESS #define NOINLINE_UNALIGNED #else /* Workaround for gcc 4.7.4 and others "optimizing" away calls to memcpy(), * and replacing them with direct (unaligned) memory accesses. * This generates broken code for eg %F on sparc. * cf https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50569 * Note that the patch for the above bug is in gcc 4.7.4, but isn't sufficient. */ #define NOINLINE_UNALIGNED ATTRIBUTE((noinline)) DECLSPEC((noinline)) #endif
9e10fe2020-06-06Marcus Comstedt #if SIZEOF_FLOAT_TYPE > SIZEOF_DOUBLE #define STRTOFLOAT_PCHARP STRTOLD_PCHARP #else #define STRTOFLOAT_PCHARP STRTOD_PCHARP #endif
38392e2015-09-06Per Hedbor static void skip_comment( PCHARP *str, ptrdiff_t *len ) { CONSUME(1); // Start '/' switch(READ())
c6c01a2003-11-14Martin Stjernholm  {
38392e2015-09-06Per Hedbor  case '*': while(*len)
c6c01a2003-11-14Martin Stjernholm  {
38392e2015-09-06Per Hedbor  while( READ() != '*' ) ; if( READ() == '/' ) return;
c6c01a2003-11-14Martin Stjernholm  } break;
38392e2015-09-06Per Hedbor  case '/': while( *len && READ()!= '\n' ) ; } } static void skip_to_token( PCHARP *str, ptrdiff_t *len ) { int worked; do { worked=0;
aa7dd02016-12-17Martin Nilsson  while(*len && wide_isspace(EXTRACT_PCHARP(*str)))
c6c01a2003-11-14Martin Stjernholm  {
aa7dd02016-12-17Martin Nilsson  worked = 1; CONSUME(1);
c6c01a2003-11-14Martin Stjernholm  }
38392e2015-09-06Per Hedbor  if( EXTRACT_PCHARP(*str) == '/' ) { skip_comment(str,len); worked=1; } }while(worked);
c6c01a2003-11-14Martin Stjernholm }
38392e2015-09-06Per Hedbor /* Note: Serious code-duplication from the lexer. */ static int pcharp_to_svalue_rec(PCHARP *str, ptrdiff_t *len)
c6c01a2003-11-14Martin Stjernholm {
38392e2015-09-06Per Hedbor  extern int parse_esc_seq_pcharp (PCHARP buf, p_wchar2 *chr, ptrdiff_t *len); struct svalue *begin = Pike_sp; PCHARP start = *str; check_stack(100);
358e942015-09-07Tobias S. Josefowitz  check_c_stack(1000);
c6c01a2003-11-14Martin Stjernholm 
38392e2015-09-06Per Hedbor  while(1)
c6c01a2003-11-14Martin Stjernholm  {
38392e2015-09-06Per Hedbor  skip_to_token(str,len); switch( READ() )
c6c01a2003-11-14Martin Stjernholm  {
38392e2015-09-06Per Hedbor  default: goto fail;
c6c01a2003-11-14Martin Stjernholm 
38392e2015-09-06Per Hedbor  case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
c6c01a2003-11-14Martin Stjernholm  {
38392e2015-09-06Per Hedbor  int base = 10; CONSUME(-1); goto read_number; case '0': switch( EXTRACT_PCHARP(*str) ) { case 'x':case 'X': base = 16; CONSUME(1); break; case 'b':case 'B': base = 2; CONSUME(1); break; case '.': CONSUME(-1); goto read_float; case 'e':case 'E': CONSUME(-1); push_float(0.0); return 1; default: base = 8; CONSUME(-1); break; } read_number: /* Integer or float. */ push_int(0); if( pcharp_to_svalue_inumber(Pike_sp-1,*str,str,base,*len) ) { if( (EXTRACT_PCHARP(*str) == '.' || EXTRACT_PCHARP(*str)=='e'|| EXTRACT_PCHARP(*str)=='E') ) { read_float: { void *integer_parse = str->ptr;
9e10fe2020-06-06Marcus Comstedt  FLOAT_TYPE res; res = STRTOFLOAT_PCHARP(start,str);
38392e2015-09-06Per Hedbor  if( integer_parse < str->ptr ) { pop_stack(); push_float(res); } } *len -= SUBTRACT_PCHARP(*str,start); if( *len < 0 ) /* this is possible for floats combined with %<len>O format. */ goto fail; } return 1;
c6c01a2003-11-14Martin Stjernholm  } }
38392e2015-09-06Per Hedbor  goto fail;
c6c01a2003-11-14Martin Stjernholm 
38392e2015-09-06Per Hedbor  case '\'': // single character. { unsigned int l = 0; struct svalue res = svalue_int_zero; ptrdiff_t used; MP_INT bigint; while(1)
c6c01a2003-11-14Martin Stjernholm  {
38392e2015-09-06Per Hedbor  p_wchar2 tmp; switch( (tmp=READ()) ) { case 0: goto fail;
c6c01a2003-11-14Martin Stjernholm 
38392e2015-09-06Per Hedbor  case '\\': if( parse_esc_seq_pcharp(*str,&tmp,&used) ) return 0; CONSUME(used); /* fallthrough. */ default: l++; if( l == sizeof(INT_TYPE)-1 ) { /* overflow possible. Switch to bignums. */ mpz_init(&bigint); mpz_set_ui(&bigint,res.u.integer); TYPEOF(res) = PIKE_T_OBJECT; }
c6c01a2003-11-14Martin Stjernholm 
38392e2015-09-06Per Hedbor  if( l >= sizeof(INT_TYPE)-1 ) { mpz_mul_2exp(&bigint,&bigint,8); mpz_add_ui(&bigint,&bigint,tmp); } else { res.u.integer <<= 8; res.u.integer |= tmp; } break; case '\'': if( TYPEOF(res) == PIKE_T_OBJECT ) { push_bignum( &bigint ); mpz_clear(&bigint); reduce_stack_top_bignum(); return 1; } *Pike_sp++ = res; return 1; } } } case '"': { struct string_builder tmp; PCHARP start; int cnt; init_string_builder(&tmp,0); start = *str; cnt = 0; for (;*len;) { switch(READ())
c6c01a2003-11-14Martin Stjernholm  { case '\"': /* End of string -- done. */ if (cnt) string_builder_append(&tmp, start, cnt);
38392e2015-09-06Per Hedbor  push_string(finish_string_builder(&tmp)); return 1;
c6c01a2003-11-14Martin Stjernholm  case '\\':
38392e2015-09-06Per Hedbor  { /* Escaped character */ p_wchar2 val=0; ptrdiff_t consumed; if( !parse_esc_seq_pcharp(*str,&val,&consumed) ) CONSUME(consumed); if (cnt) string_builder_append(&tmp, start, cnt); string_builder_putchar(&tmp, val); *str=start; } continue;
c6c01a2003-11-14Martin Stjernholm  case '\n':
38392e2015-09-06Per Hedbor  free_string_builder(&tmp); goto fail;
c6c01a2003-11-14Martin Stjernholm  default: cnt++; continue; } }
38392e2015-09-06Per Hedbor  /* Unterminated string -- fail. */ free_string_builder(&tmp); goto fail; }
c6c01a2003-11-14Martin Stjernholm 
38392e2015-09-06Per Hedbor  case '(': // container. { int num=0; p_wchar2 tmp; #define CHECK_STACK_ADD(ADD) do{ \ if(Pike_sp-begin > 100 ) { \ ADD(Pike_sp-begin); \ begin= Pike_sp; \ num++; \ } \ }while(0) #define FINISH(ADD) do { \ num++; \ ADD(Pike_sp-begin); \ goto container_finished; \ } while(0) switch( READ() )
c6c01a2003-11-14Martin Stjernholm  {
38392e2015-09-06Per Hedbor  case '[': while(1) { skip_to_token(str,len); if(EXTRACT_PCHARP(*str) == ']' ) { CONSUME(1); FINISH(f_aggregate_mapping); } if( !pcharp_to_svalue_rec(str,len) ) goto fail; skip_to_token(str,len); if( READ() != ':' ) goto fail; if(!pcharp_to_svalue_rec(str,len)) goto fail; skip_to_token(str,len); tmp = READ(); if( tmp == ']' ) FINISH(f_aggregate_mapping); if( tmp != ',' ) goto fail; CHECK_STACK_ADD(f_aggregate_mapping); } break;
c6c01a2003-11-14Martin Stjernholm 
38392e2015-09-06Per Hedbor  case '{': while(1) { skip_to_token(str,len); if(EXTRACT_PCHARP(*str)=='}' ) { CONSUME(1); FINISH(f_aggregate); } if( !pcharp_to_svalue_rec(str,len) ) goto fail; skip_to_token(str,len); tmp=READ(); if(tmp == '}' ) FINISH(f_aggregate); if( tmp != ',' ) goto fail; CHECK_STACK_ADD(f_aggregate); } break; case '<': while(1) { skip_to_token(str,len); if(EXTRACT_PCHARP(*str)=='>' ) { CONSUME(1); FINISH(f_aggregate_multiset); }
f316752016-12-17Martin Nilsson  if( !pcharp_to_svalue_rec(str,len) ) goto fail;
38392e2015-09-06Per Hedbor  skip_to_token(str,len); tmp=READ(); if(tmp == '>' ) FINISH(f_aggregate_multiset); if( tmp != ',' ) goto fail; CHECK_STACK_ADD(f_aggregate_multiset); } break; default: /* Not a valid container. */ goto fail; } #undef FINISH #undef CHECK_STACK_ADD /* end of container. */ container_finished: if( READ() != ')' ) goto fail; if(num > 1 ) f_add(num); return 1; } } }
c6c01a2003-11-14Martin Stjernholm 
38392e2015-09-06Per Hedbor  fail: pop_n_elems(Pike_sp-begin); return 0; }
c6c01a2003-11-14Martin Stjernholm 
13670c2015-05-25Martin Nilsson 
38392e2015-09-06Per Hedbor static void *pcharp_to_svalue_percent_o(struct svalue *res, PCHARP str, ptrdiff_t len) { SET_SVAL(*res, T_INT, NUMBER_UNDEFINED, integer, 0); if( pcharp_to_svalue_rec( &str, &len ) ) { *res = *--Pike_sp; return str.ptr;
c6c01a2003-11-14Martin Stjernholm  } return NULL; } /* flags: * operators: %d
eb081d2007-04-28Per Hedbor  %H
c6c01a2003-11-14Martin Stjernholm  %s %f %c %n %[ %% %O */ 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 ptrdiff_t PIKE_CONCAT(read_set,SIZE) ( \ PIKE_CONCAT(p_wchar,SIZE) *match, \ ptrdiff_t cnt, \ struct sscanf_set *set, \
558e912014-10-05Martin Nilsson  ptrdiff_t match_len) \
c6c01a2003-11-14Martin Stjernholm { \
9176812008-07-01Marcus Comstedt  p_wchar2 e, last = 0; \
d689592008-07-09Martin Stjernholm  MATCH_IS_WIDE( int set_size=0; ) \
c6c01a2003-11-14Martin Stjernholm  \ if(cnt>=match_len) \
b8b8af2014-08-27Henrik Grubbström (Grubba)  Pike_error("Unterminated sscanf set.\n"); \
c6c01a2003-11-14Martin Stjernholm  \
21b12a2014-09-03Martin Nilsson  memset(set->c, 0, sizeof(set->c)); \
c6c01a2003-11-14Martin Stjernholm  set->a=0; \ \
dc8c3e2008-05-14Marcus Comstedt  if(match[cnt]=='^' && \ (cnt+2>=match_len || match[cnt+1]!='-' || \
c9562b2014-10-05Martin Nilsson  match[cnt+2]==']')) \
c6c01a2003-11-14Martin Stjernholm  { \ set->neg=1; \ cnt++; \ if(cnt>=match_len) \
19961b2017-04-08Martin Nilsson  Pike_error("Unterminated negated sscanf set.\n"); \
c6c01a2003-11-14Martin Stjernholm  }else{ \ set->neg=0; \ } \ \ if(match[cnt]==']' || match[cnt]=='-') \ { \ set->c[last=match[cnt]]=1; \ cnt++; \ if(cnt>=match_len) \
b8b8af2014-08-27Henrik Grubbström (Grubba)  Pike_error("Empty sscanf range.\n"); \
c6c01a2003-11-14Martin Stjernholm  } \ \
0b55392008-05-15Marcus Comstedt  for(;match[cnt]!=']';) \
c6c01a2003-11-14Martin Stjernholm  { \ if(match[cnt]=='-') \ { \ cnt++; \ if(cnt>=match_len) \
b8b8af2014-08-27Henrik Grubbström (Grubba)  Pike_error("Unterminated sscanf range.\n"); \
c6c01a2003-11-14Martin Stjernholm  \ if(match[cnt]==']') \ { \ set->c['-']=1; \ break; \ } \ \
dc8c3e2008-05-14Marcus Comstedt  if(last > match[cnt]) \
b8b8af2014-08-27Henrik Grubbström (Grubba)  Pike_error("Inverted sscanf range [%c-%c].\n", \ last, match[cnt]); \
c6c01a2003-11-14Martin Stjernholm  \
d689592008-07-09Martin Stjernholm MATCH_IS_WIDE( \
9176812008-07-01Marcus Comstedt  if(last < (p_wchar2)sizeof(set->c) && last >= 0) \
c6c01a2003-11-14Martin Stjernholm  { \
9176812008-07-01Marcus Comstedt  if(match[cnt] < (p_wchar2)sizeof(set->c)) \
c6c01a2003-11-14Martin Stjernholm  { \ ) \ for(e=last;e<=match[cnt];e++) set->c[e]=1; \
d689592008-07-09Martin Stjernholm MATCH_IS_WIDE( \
c6c01a2003-11-14Martin Stjernholm  }else{ \
9176812008-07-01Marcus Comstedt  for(e=last;e<(p_wchar2)sizeof(set->c);e++) \
c6c01a2003-11-14Martin Stjernholm  set->c[e]=1; \ \ check_stack(2); \ push_int(256); \ push_int(match[cnt]); \ set_size++; \ } \ } \ else \ { \
19961b2017-04-08Martin Nilsson  Pike_sp[-1].u.integer=match[cnt]; \
c6c01a2003-11-14Martin Stjernholm  } \ ) \
0b55392008-05-15Marcus Comstedt  } else { \ last=match[cnt]; \
d689592008-07-09Martin Stjernholm MATCH_IS_WIDE( \
9176812008-07-01Marcus Comstedt  if(last < (p_wchar2)sizeof(set->c) && last >= 0) \ ) \
0b55392008-05-15Marcus Comstedt  set->c[last]=1; \
d689592008-07-09Martin Stjernholm MATCH_IS_WIDE( \
0b55392008-05-15Marcus Comstedt  else{ \ if(set_size && \
19961b2017-04-08Martin Nilsson  ((p_wchar2)Pike_sp[-1].u.integer) == last-1) \
0b55392008-05-15Marcus Comstedt  { \
19961b2017-04-08Martin Nilsson  Pike_sp[-1].u.integer++; \
0b55392008-05-15Marcus Comstedt  }else{ \ check_stack(2); \
9176812008-07-01Marcus Comstedt  push_int(last); \ push_int(last); \
0b55392008-05-15Marcus Comstedt  set_size++; \ } \
c6c01a2003-11-14Martin Stjernholm  } \
0b55392008-05-15Marcus Comstedt  ) \
c6c01a2003-11-14Martin Stjernholm  } \
0b55392008-05-15Marcus Comstedt  cnt++; \ if(cnt>=match_len) \
b8b8af2014-08-27Henrik Grubbström (Grubba)  Pike_error("Unterminated sscanf set.\n"); \
c6c01a2003-11-14Martin Stjernholm  } \ \
d689592008-07-09Martin Stjernholm MATCH_IS_WIDE( \
c6c01a2003-11-14Martin Stjernholm  if(set_size) \ { \ INT32 *order; \ set->a=aggregate_array(set_size*2); \ order=get_switch_order(set->a); \
9176812008-07-01Marcus Comstedt  for(e=0;e<(p_wchar2)set->a->size;e+=2) \
c6c01a2003-11-14Martin Stjernholm  { \ if(order[e]+1 != order[e+1] && \ order[e+1]+1 != order[e]) { \ free_array(set->a); \ set->a=0; \
0ec7522014-04-27Martin Nilsson  free(order); \
d689592008-07-09Martin Stjernholm  Pike_error("Overlapping ranges in sscanf not supported.\n"); \
c6c01a2003-11-14Martin Stjernholm  } \ } \ \ order_array(set->a,order); \
0ec7522014-04-27Martin Nilsson  free(order); \
c6c01a2003-11-14Martin Stjernholm  } \ ) \ return cnt; \ } /* Parse binary IEEE strings on a machine which uses a different kind of floating point internally */ #ifdef NEED_CUSTOM_IEEE
d306732017-07-16Martin Nilsson static inline FLOAT_TYPE low_parse_IEEE_float(const char *b, int sz)
c6c01a2003-11-14Martin Stjernholm { unsigned INT32 f, extra_f; int s, e; unsigned char x[4]; double r;
86d8242017-07-17Marcus Comstedt  if (sz < 0) { x[0] = EXTRACT_UCHAR(b-sz-1); x[1] = EXTRACT_UCHAR(b-sz-2); x[2] = EXTRACT_UCHAR(b-sz-3); x[3] = EXTRACT_UCHAR(b-sz-4); } else { x[0] = EXTRACT_UCHAR(b); x[1] = EXTRACT_UCHAR(b+1); x[2] = EXTRACT_UCHAR(b+2); x[3] = EXTRACT_UCHAR(b+3); }
c6c01a2003-11-14Martin Stjernholm  s = ((x[0]&0x80)? 1 : 0);
86d8242017-07-17Marcus Comstedt  if(sz==4 || sz==-4) {
c6c01a2003-11-14Martin Stjernholm  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];
86d8242017-07-17Marcus Comstedt  if (sz < 0) extra_f = (((unsigned INT32)EXTRACT_UCHAR(b+3))<<24)| (((unsigned INT32)EXTRACT_UCHAR(b+2))<<16)| (((unsigned INT32)EXTRACT_UCHAR(b+1))<<8)| ((unsigned INT32)EXTRACT_UCHAR(b)); else 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));
c6c01a2003-11-14Martin Stjernholm  if(e==2047) e = 9999; else if(e>0) { f |= 0x00100000; e -= 1023+20; } else e -= 1022+20; }
d306732017-07-16Martin Nilsson 
c6c01a2003-11-14Martin Stjernholm  if(e>=9999)
d306732017-07-16Martin Nilsson  {
c6c01a2003-11-14Martin Stjernholm  if(f||extra_f) { /* NAN */ return (FLOAT_TYPE)MAKE_NAN(); } else { /* +/- Infinity */
d306732017-07-16Martin Nilsson  return (FLOAT_TYPE)MAKE_INF() * (s? -1:1);
c6c01a2003-11-14Martin Stjernholm  }
d306732017-07-16Martin Nilsson  }
c6c01a2003-11-14Martin Stjernholm  r = (double)f; if(extra_f) r += ((double)extra_f)/4294967296.0;
159a2b2014-09-03Martin Nilsson  return (FLOAT_TYPE)(s? -ldexp(r, e):ldexp(r, e));
c6c01a2003-11-14Martin Stjernholm } #endif
d0233c2018-07-05Henrik Grubbström (Grubba) static FLOAT_TYPE NOINLINE_UNALIGNED extract_float_be(const char * x) {
c6c01a2003-11-14Martin Stjernholm #ifdef FLOAT_IS_IEEE_BIG
86d8242017-07-17Marcus Comstedt  float f;
a2133d2014-04-17Arne Goedeke  memcpy(&f, x, sizeof(f));
86d8242017-07-17Marcus Comstedt  return f;
a2133d2014-04-17Arne Goedeke #elif FLOAT_IS_IEEE_LITTLE
86d8242017-07-17Marcus Comstedt  float f;
a2133d2014-04-17Arne Goedeke  unsigned INT32 tmp = get_unaligned32(x); tmp = bswap32(tmp); memcpy(&f, &tmp, sizeof(f));
86d8242017-07-17Marcus Comstedt  return f;
c6c01a2003-11-14Martin Stjernholm #else
86d8242017-07-17Marcus Comstedt  return low_parse_IEEE_float(x, 4);
c6c01a2003-11-14Martin Stjernholm #endif
a2133d2014-04-17Arne Goedeke }
c6c01a2003-11-14Martin Stjernholm 
d0233c2018-07-05Henrik Grubbström (Grubba) static FLOAT_TYPE NOINLINE_UNALIGNED extract_double_be(const char * x) {
d993802017-07-17Martin Nilsson #ifdef DOUBLE_IS_IEEE_BIG
86d8242017-07-17Marcus Comstedt  double f;
a2133d2014-04-17Arne Goedeke  memcpy(&f, x, sizeof(f));
86d8242017-07-17Marcus Comstedt  return f;
d993802017-07-17Martin Nilsson #elif DOUBLE_IS_IEEE_LITTLE
86d8242017-07-17Marcus Comstedt  double f; #ifdef UINT64
30f5b22016-04-09Martin Nilsson  UINT64 tmp = get_unaligned64(x);
a2133d2014-04-17Arne Goedeke  tmp = bswap64(tmp);
c6c01a2003-11-14Martin Stjernholm #else
86d8242017-07-17Marcus Comstedt  char tmp[8]; tmp[7] = x[0]; tmp[6] = x[1]; tmp[5] = x[2]; tmp[4] = x[3]; tmp[3] = x[4]; tmp[2] = x[5]; tmp[1] = x[6]; tmp[0] = x[7];
a2133d2014-04-17Arne Goedeke #endif
86d8242017-07-17Marcus Comstedt  memcpy(&f, &tmp, sizeof(f));
a2133d2014-04-17Arne Goedeke  return f;
86d8242017-07-17Marcus Comstedt #else return low_parse_IEEE_float(x, 8); #endif
a2133d2014-04-17Arne Goedeke }
d0233c2018-07-05Henrik Grubbström (Grubba) static FLOAT_TYPE NOINLINE_UNALIGNED extract_float_le(const char * x) {
a2133d2014-04-17Arne Goedeke #ifdef FLOAT_IS_IEEE_LITTLE
86d8242017-07-17Marcus Comstedt  float f;
a2133d2014-04-17Arne Goedeke  memcpy(&f, x, sizeof(f));
86d8242017-07-17Marcus Comstedt  return f;
a2133d2014-04-17Arne Goedeke #elif FLOAT_IS_IEEE_BIG
86d8242017-07-17Marcus Comstedt  float f;
a2133d2014-04-17Arne Goedeke  unsigned INT32 tmp = get_unaligned32(x); tmp = bswap32(tmp); memcpy(&f, &tmp, sizeof(f));
86d8242017-07-17Marcus Comstedt  return f;
c6c01a2003-11-14Martin Stjernholm #else
86d8242017-07-17Marcus Comstedt  return low_parse_IEEE_float(x, -4);
c6c01a2003-11-14Martin Stjernholm #endif
a2133d2014-04-17Arne Goedeke }
d0233c2018-07-05Henrik Grubbström (Grubba) static FLOAT_TYPE NOINLINE_UNALIGNED extract_double_le(const char * x) {
d993802017-07-17Martin Nilsson #ifdef DOUBLE_IS_IEEE_LITTLE
86d8242017-07-17Marcus Comstedt  double f;
a2133d2014-04-17Arne Goedeke  memcpy(&f, x, sizeof(f));
86d8242017-07-17Marcus Comstedt  return f;
d993802017-07-17Martin Nilsson #elif DOUBLE_IS_IEEE_BIG
86d8242017-07-17Marcus Comstedt  double f; #ifdef UINT64
30f5b22016-04-09Martin Nilsson  UINT64 tmp = get_unaligned64(x);
a2133d2014-04-17Arne Goedeke  tmp = bswap64(tmp); #else
86d8242017-07-17Marcus Comstedt  char tmp[8]; tmp[7] = x[0]; tmp[6] = x[1]; tmp[5] = x[2]; tmp[4] = x[3]; tmp[3] = x[4]; tmp[2] = x[5]; tmp[1] = x[6]; tmp[0] = x[7];
c6c01a2003-11-14Martin Stjernholm #endif
86d8242017-07-17Marcus Comstedt  memcpy(&f, &tmp, sizeof(f));
a2133d2014-04-17Arne Goedeke  return f;
86d8242017-07-17Marcus Comstedt #else return low_parse_IEEE_float(x, -8); #endif
a2133d2014-04-17Arne Goedeke } #define EXTRACT_FLOAT(SVAL, input, shift, fun) do { \ char x[4]; \ if (shift == 0) { \ memcpy(x, input, sizeof(x)); \ } else { \ PCHARP tmp = MKPCHARP(input, shift); \ size_t i; \ for (i = 0; i < sizeof(x); INC_PCHARP(tmp, 1), i++) \ x[i] = EXTRACT_PCHARP(tmp); \ } \ (SVAL).u.float_number = fun(x); \ } while (0) #define EXTRACT_DOUBLE(SVAL, input, shift, fun) do { \ char x[8]; \ if (shift == 0) { \ memcpy(x, input, sizeof(x)); \ } else { \ PCHARP tmp = MKPCHARP(input, shift); \ size_t i; \ for (i = 0; i < sizeof(x); INC_PCHARP(tmp, 1), i++) \ x[i] = EXTRACT_PCHARP(tmp); \ } \ (SVAL).u.float_number = fun(x); \ } while (0)
d0233c2018-07-05Henrik Grubbström (Grubba) static struct pike_string * NOINLINE_UNALIGNED get_string_slice( void *input, int shift, ptrdiff_t offset, ptrdiff_t len, struct pike_string *str )
11ff452015-08-24Per Hedbor {
db40b02015-09-01Per Hedbor  if( !shift && str )
11ff452015-08-24Per Hedbor  return string_slice( str, offset, len );
db40b02015-09-01Per Hedbor  return make_shared_binary_pcharp(MKPCHARP(((char *)input)+(offset<<shift),shift), len);
11ff452015-08-24Per Hedbor }
c6c01a2003-11-14Martin Stjernholm /* INT32 very_low_sscanf_{0,1,2}_{0,1,2}(p_wchar *input, ptrdiff_t input_len, * p_wchar *match, ptrdiff_t match_len, * ptrdiff_t *chars_matched, * int *success) * * Perform the actual parsing. * * Arguments: * input, input_len Input data to parse. * match, match_len Format string. * chars_matched Gets set to the number of characters * in the input that were advanced. * success Gets set to 1 on success. * * Returns: * Returns the number of %-directives that were successfully matched. * Pushes non-ignored matches on the Pike stack in the order they * were matched. *
9a2ff02014-08-28Per Hedbor  * FIXME: success is only used internally, and should probably be * gotten rid of.
c6c01a2003-11-14Martin Stjernholm  */ #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, \
11ff452015-08-24Per Hedbor  int *success, \ struct pike_string *pstr) \
c6c01a2003-11-14Martin Stjernholm { \ struct svalue sval; \ INT32 matches, arg; \
e02b4f2010-11-21Henrik Grubbström (Grubba)  ptrdiff_t cnt, eye, start_eye, e, field_length = 0, truncated = 0; \ int no_assign = 0, minus_flag = 0, plus_flag = 0, truncate = 0; \
c6c01a2003-11-14Martin Stjernholm  struct sscanf_set set; \ \ \ 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]=='%') \ { \
b8b8af2014-08-27Henrik Grubbström (Grubba)  Pike_fatal("Failed to escape in sscanf.\n"); \
c6c01a2003-11-14Martin Stjernholm  } \ ); \ \ no_assign=0; \ field_length=-1; \ minus_flag=0; \ plus_flag=0; \
e02b4f2010-11-21Henrik Grubbström (Grubba)  truncate=0; \ start_eye = eye; \
c6c01a2003-11-14Martin Stjernholm  \ cnt++; \ if(cnt>=match_len) \
b8b8af2014-08-27Henrik Grubbström (Grubba)  Pike_error("Missing format specifier in sscanf format string.\n"); \
c6c01a2003-11-14Martin Stjernholm  \ while(1) \ { \ switch(match[cnt]) \ { \ case '*': \ no_assign=1; \ cnt++; \ if(cnt>=match_len) \
b8b8af2014-08-27Henrik Grubbström (Grubba)  Pike_error("Missing format specifier in ignored sscanf " \ "format string.\n"); \
c6c01a2003-11-14Martin Stjernholm  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 '+': \ plus_flag=1; \ cnt++; \ continue; \ \
e02b4f2010-11-21Henrik Grubbström (Grubba)  case '!': \ truncate=1; \ cnt++; \ continue; \ \
c6c01a2003-11-14Martin Stjernholm  case '{': \ { \ ONERROR err; \ ptrdiff_t tmp; \ for(e=cnt+1,tmp=1;tmp;e++) \ { \ if(e>=match_len) \ { \ Pike_error("Missing %%} in format string.\n"); \
9282fd2015-09-27Martin Nilsson  UNREACHABLE(break); \
c6c01a2003-11-14Martin Stjernholm  } \ if(match[e]=='%') \ { \ switch(match[e+1]) \ { \ case '%': e++; break; \ case '}': tmp--; break; \ case '{': tmp++; break; \ } \ } \ } \
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(sval, T_ARRAY, 0, array, allocate_array(0)); \
c6c01a2003-11-14Martin Stjernholm  SET_ONERROR(err, do_free_array, sval.u.array); \ \ while(input_len-eye) \
19961b2017-04-08Martin Nilsson  { \
c6c01a2003-11-14Martin Stjernholm  int yes; \
19961b2017-04-08Martin Nilsson  struct svalue *save_sp=Pike_sp; \
c6c01a2003-11-14Martin Stjernholm  PIKE_CONCAT4(very_low_sscanf_, INPUT_SHIFT, _, MATCH_SHIFT)( \ input+eye, \ input_len-eye, \ match+cnt+1, \ e-cnt-2, \ &tmp, \
11ff452015-08-24Per Hedbor  &yes,0); \
c6c01a2003-11-14Martin Stjernholm  if(yes && tmp) \ { \
19961b2017-04-08Martin Nilsson  f_aggregate((INT32)(Pike_sp-save_sp)); \ sval.u.array=append_array(sval.u.array,Pike_sp-1); \
c6c01a2003-11-14Martin Stjernholm  pop_stack(); \ eye+=tmp; \ }else{ \
19961b2017-04-08Martin Nilsson  pop_n_elems(Pike_sp-save_sp); \
c6c01a2003-11-14Martin Stjernholm  break; \ } \ } \ cnt=e; \ UNSET_ONERROR(err); \ break; \ } \ \ case 'c': \ { \
d689592008-07-09Martin Stjernholm INPUT_IS_WIDE( \
c6c01a2003-11-14Martin Stjernholm  int e; \ ) \
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(sval, T_INT, NUMBER_NUMBER, integer, 0); \
c6c01a2003-11-14Martin Stjernholm  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; \ } \
d689592008-07-09Martin Stjernholm INPUT_IS_WIDE( \
c6c01a2003-11-14Martin Stjernholm  for(e=0;e<field_length;e++) \ { \
19961b2017-04-08Martin Nilsson  if((unsigned INT32) input[eye+e] > 255) \
c6c01a2003-11-14Martin Stjernholm  { \ chars_matched[0]=eye; \ return matches; \ } \ } \ ) \ sval.u.integer=0; \ if (minus_flag) \ { \
f7ce892017-04-08Martin Nilsson  int pos=0; \
c6c01a2003-11-14Martin Stjernholm  if (field_length >= 0) { \ pos = (eye += field_length); \ } \ if (plus_flag && (--field_length >= 0)) { \ sval.u.integer = (signed char)input[--pos]; \ } \ while(--field_length >= 0) \ { \ 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[--pos]); \ o_or(); \ } \ dmalloc_touch_svalue(Pike_sp-1); \
19961b2017-04-08Martin Nilsson  sval=*--Pike_sp; \
c6c01a2003-11-14Martin Stjernholm  break; \ } \ sval.u.integer<<=8; \ sval.u.integer |= input[--pos]; \ } \ } else { \ if (plus_flag && (--field_length >= 0)) { \ sval.u.integer = (signed char)input[eye++]; \ } \ while(--field_length >= 0) \ { \ 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++; \ } \ dmalloc_touch_svalue(Pike_sp-1); \
19961b2017-04-08Martin Nilsson  sval=*--Pike_sp; \
c6c01a2003-11-14Martin Stjernholm  break; \ } \ sval.u.integer<<=8; \ sval.u.integer |= input[eye]; \ eye++; \ } \ } \ break; \ } \
eb081d2007-04-28Per Hedbor  \
f7ce892017-04-08Martin Nilsson  case 'H': \ { \
6594742012-04-17Per Hedbor  unsigned long len=0; \
f7ce892017-04-08Martin Nilsson  if(field_length == -1) \ field_length=1; \ if(field_length == 0) \ Pike_error("%%H size field is 0.\n"); \ if(eye+field_length > input_len) \ { \ chars_matched[0]=eye; \ return matches; \ } \ INPUT_IS_WIDE ( \ for(e=0;e<field_length;e++) \ { \ if((unsigned INT32) input[eye+e] > 255) \ { \ chars_matched[0]=eye; \ return matches; \ } \ } \ ); \ if (minus_flag) \ { \ int pos=0; \ pos = (eye += field_length); \ while(--field_length >= 0) \ { \ len<<=8; \ len |= input[--pos]; \ } \ } else { \ while(--field_length >= 0) \ { \ len<<=8; \ len |= input[eye]; \ eye++; \ } \ } \ if(len > (unsigned long)(input_len-eye)) \ { \ chars_matched[0]=eye-field_length; \ return matches; \ } \ if (no_assign) { \ no_assign = 2; \ } else { \ SET_SVAL(sval, T_STRING, 0, string, \ PIKE_CONCAT(make_shared_binary_string, \ INPUT_SHIFT)(input+eye, len)); \ } \ eye+=len; \ break; \ } \
c6c01a2003-11-14Martin Stjernholm  \ 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, &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; \
017b572011-10-28Henrik Grubbström (Grubba)  FLOAT_TYPE f; \
c6c01a2003-11-14Martin Stjernholm  \ if(eye>=input_len) \ { \ chars_matched[0]=eye; \ return matches; \ } \
9e10fe2020-06-06Marcus Comstedt  f = (FLOAT_TYPE)STRTOFLOAT_PCHARP(MKPCHARP(input+eye, \ INPUT_SHIFT),&t2); \
c6c01a2003-11-14Martin Stjernholm  t = (PIKE_CONCAT(p_wchar, INPUT_SHIFT) *)(t2.ptr); \ if(input + eye == t) \ { \ chars_matched[0]=eye; \ return matches; \ } \ eye=t-input; \
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(sval, T_FLOAT, 0, float_number, f); \
c6c01a2003-11-14Martin Stjernholm  break; \ } \ \ case 'F': \ if(field_length == -1) field_length = 4; \ if(field_length != 4 && field_length != 8) \
f7ce892017-04-08Martin Nilsson  Pike_error("Invalid IEEE width %ld in sscanf format string.\n", \ (long)field_length); \ if(eye+field_length > input_len) \
c6c01a2003-11-14Martin Stjernholm  { \ chars_matched[0]=eye; \ return matches; \ } \
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(sval, T_FLOAT, 0, float_number, 0.0); \
c6c01a2003-11-14Martin Stjernholm  switch(field_length) { \ case 4: \
f7ce892017-04-08Martin Nilsson  if (minus_flag) \ EXTRACT_FLOAT(sval, input+eye, INPUT_SHIFT, extract_float_le); \ else \ EXTRACT_FLOAT(sval, input+eye, INPUT_SHIFT, extract_float_be); \ eye += 4; \ break; \
c6c01a2003-11-14Martin Stjernholm  case 8: \
f7ce892017-04-08Martin Nilsson  if (minus_flag) \ EXTRACT_DOUBLE(sval, input+eye, INPUT_SHIFT, extract_double_le); \ else \ EXTRACT_DOUBLE(sval, input+eye, INPUT_SHIFT, extract_double_be); \
c6c01a2003-11-14Martin Stjernholm  eye += 8; \ break; \ } \ break; \ \ case 's': \ if(field_length != -1) \ { \ if(input_len - eye < field_length) \ { \ chars_matched[0]=eye; \ return matches; \ } \ \
4e62462005-07-31Jonas Wallden  if (no_assign) { \ no_assign = 2; \ } else { \
11ff452015-08-24Per Hedbor  SET_SVAL(sval, T_STRING, 0, string, \ get_string_slice(input,INPUT_SHIFT,eye, \ field_length,pstr)); \
4e62462005-07-31Jonas Wallden  } \
c6c01a2003-11-14Martin Stjernholm  eye+=field_length; \ break; \ } \ \ if(cnt+1>=match_len) \ { \
4e62462005-07-31Jonas Wallden  if (no_assign) { \ no_assign = 2; \ } else { \
11ff452015-08-24Per Hedbor  SET_SVAL(sval, T_STRING, 0, string, \ get_string_slice(input,INPUT_SHIFT,eye, \ input_len-eye,pstr)); \
4e62462005-07-31Jonas Wallden  } \
c6c01a2003-11-14Martin Stjernholm  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; \ \ e = cnt; \ 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 0: \ /* FIXME: Should really look at the match len */ \ Pike_error("%% without conversion specifier.\n"); \ break; \ \ case 'n': \ s++; \ /* Advance the end string start pointer */ \ end_str_start = s; \ e = s - match; \ goto test_again; \ \ case 's': \ Pike_error("Illegal to have two adjecent %%s.\n"); \
9282fd2015-09-27Martin Nilsson  UNREACHABLE(return 0); \
c6c01a2003-11-14Martin Stjernholm  \ /* sscanf("foo-bar","%s%d",a,b) might not work as expected */ \ case 'd': \
21b12a2014-09-03Martin Nilsson  memset(set.c, 1, sizeof(set.c)); \
c6c01a2003-11-14Martin Stjernholm  for(e='0';e<='9';e++) set.c[e]=0; \ set.c['-']=0; \ goto match_set; \ \ case 'o': \
21b12a2014-09-03Martin Nilsson  memset(set.c, 1, sizeof(set.c)); \
c6c01a2003-11-14Martin Stjernholm  for(e='0';e<='7';e++) set.c[e]=0; \ goto match_set; \ \ case 'x': \
21b12a2014-09-03Martin Nilsson  memset(set.c, 1, sizeof(set.c)); \
c6c01a2003-11-14Martin Stjernholm  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': \
21b12a2014-09-03Martin Nilsson  memset(set.c, 1, sizeof(set.c)); \
c6c01a2003-11-14Martin Stjernholm  for(e='0';e<='9';e++) set.c[e]=0; \ set.c['-']=0; \ goto match_set; \ \ case 'f': \
21b12a2014-09-03Martin Nilsson  memset(set.c, 1, sizeof(set.c)); \
c6c01a2003-11-14Martin Stjernholm  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, \
f7ce892017-04-08Martin Nilsson  match_len); \
c6c01a2003-11-14Martin Stjernholm  set.neg=!set.neg; \ goto match_set; \ } \ } \ \ contains_percent_percent=0; \ \ for(;e<match_len;e++) \ { \ if(match[e]=='%') \ { \ if(match[e+1]=='%') \ { \ contains_percent_percent=1; \ e++; \ }else{ \ break; \ } \ } \ } \ \ end_str_end=match+e; \ \ if (end_str_end == end_str_start) { \
4e62462005-07-31Jonas Wallden  if (no_assign) { \ no_assign = 2; \ } else { \
11ff452015-08-24Per Hedbor  SET_SVAL(sval, T_STRING, 0, string, \ get_string_slice(input,INPUT_SHIFT,eye, \ input_len-eye,pstr)); \
4e62462005-07-31Jonas Wallden  } \
c6c01a2003-11-14Martin Stjernholm  eye=input_len; \ break; \ } else if(!contains_percent_percent) \ { \
2934f42004-03-07Martin Nilsson  struct pike_mem_searcher searcher; \
c6c01a2003-11-14Martin Stjernholm  PIKE_CONCAT(p_wchar, INPUT_SHIFT) *s2; \
2934f42004-03-07Martin Nilsson  pike_init_memsearch(&searcher, \ MKPCHARP(end_str_start, MATCH_SHIFT), \
c6c01a2003-11-14Martin Stjernholm  end_str_end - end_str_start, \
2934f42004-03-07Martin Nilsson  input_len - eye); \
380db72004-03-07Martin Nilsson  s2 = searcher.mojt.vtab-> PIKE_CONCAT(func,INPUT_SHIFT) \ (searcher.mojt.data, input+eye, input_len-eye); \
c6c01a2003-11-14Martin Stjernholm  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; \ } \ \
4e62462005-07-31Jonas Wallden  if (no_assign) { \ no_assign = 2; \ } else { \
11ff452015-08-24Per Hedbor  SET_SVAL(sval, T_STRING, 0, string, \ get_string_slice(input,INPUT_SHIFT,start, \ eye-start,pstr)); \
4e62462005-07-31Jonas Wallden  } \
c6c01a2003-11-14Martin Stjernholm  \ cnt=end_str_end-match-1; \ eye=new_eye; \ break; \ } \ \ case '[': \ cnt=PIKE_CONCAT(read_set,MATCH_SHIFT)(match,cnt+1, \
558e912014-10-05Martin Nilsson  &set,match_len); \
c6c01a2003-11-14Martin Stjernholm  \ match_set: \ { \ int len = input_len; \ if (field_length != -1) { \ len = eye + field_length; \ if (len > input_len) { \ /* Mismatch -- too little data */ \ chars_matched[0]=eye; \ return matches; \ } \ } \ for(e=eye;eye<len;eye++) \ { \
d689592008-07-09Martin Stjernholm INPUT_IS_WIDE( \
558e912014-10-05Martin Nilsson  if((unsigned INT32) input[eye] < sizeof(set.c)) \
c6c01a2003-11-14Martin Stjernholm  { \ ) \ if(set.c[input[eye]] == set.neg) \ break; \
d689592008-07-09Martin Stjernholm INPUT_IS_WIDE( \
c6c01a2003-11-14Martin Stjernholm  }else{ \ if(set.a) \ { \ INT32 x; \ struct svalue tmp; \
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(tmp, T_INT, NUMBER_NUMBER, \ integer, input[eye]); \
c6c01a2003-11-14Martin Stjernholm  x=switch_lookup(set.a, &tmp); \ if( set.neg != (x<0 && (x&1)) ) break; \ }else{ \ if(!set.neg) break; \ } \ } \ ) \ } \ if ((field_length != -1) && (eye != len)) { \ /* Couldn't read the entire field. Fail. */ \ chars_matched[0]=e; \ return matches; \ } \ } \ if(set.a) { free_array(set.a); set.a=0; } \
4e62462005-07-31Jonas Wallden  if (no_assign) { \ no_assign = 2; \ } else { \
11ff452015-08-24Per Hedbor  SET_SVAL(sval, T_STRING, 0, string, \ get_string_slice(input,INPUT_SHIFT,e, \ eye-e,pstr)); \
4e62462005-07-31Jonas Wallden  } \
c6c01a2003-11-14Martin Stjernholm  break; \ \ case 'O': \ { \ PIKE_CONCAT(p_wchar, INPUT_SHIFT) *cont; \ if(eye>=input_len) \ { \ chars_matched[0]=eye; \ return matches; \ } \ if ((field_length == -1) || \ ((input_len - eye) < field_length)) \ field_length = input_len - eye; \ \ cont = \ pcharp_to_svalue_percent_o(&sval, \ MKPCHARP(input+eye, INPUT_SHIFT), \ field_length); \ if(!cont) \ { \ chars_matched[0]=eye; \ return matches; \ } \ eye = cont-input; \ \ break; \ } \ \ case 'n': \
017b572011-10-28Henrik Grubbström (Grubba)  SET_SVAL(sval, T_INT, NUMBER_NUMBER, integer, \
e9e7032016-02-12Martin Nilsson  (INT32)(eye - truncated)); \
c6c01a2003-11-14Martin Stjernholm  break; \ \ default: \ Pike_error("Unknown sscanf token %%%c(0x%02x)\n", \ match[cnt], match[cnt]); \ } \ break; \ } \ matches++; \
e02b4f2010-11-21Henrik Grubbström (Grubba)  if (truncate) { \ truncated += eye - start_eye; \ } \
c6c01a2003-11-14Martin Stjernholm  \ if(no_assign) \ { \
4e62462005-07-31Jonas Wallden  if (no_assign == 1) \ free_svalue(&sval); \ } else { \
c6c01a2003-11-14Martin Stjernholm  check_stack(1); \
19961b2017-04-08Martin Nilsson  *Pike_sp++=sval; \
c6c01a2003-11-14Martin Stjernholm  dmalloc_touch_svalue(Pike_sp-1); \
1f4d702011-10-28Henrik Grubbström (Grubba)  DO_IF_DEBUG(INVALIDATE_SVAL(sval)); \
c6c01a2003-11-14Martin Stjernholm  } \ } \ chars_matched[0]=eye; \ success[0]=1; \ return matches; \ } /* Confusing? Yes - Hubbe */
d689592008-07-09Martin Stjernholm /* Now slightly less confusing macro names, at least. /mast */
c6c01a2003-11-14Martin Stjernholm 
d689592008-07-09Martin Stjernholm /* MATCH_IS_WIDE(X) is X if the match set is wide. * INPUT_IS_WIDE(X) is X if the input is wide.
c6c01a2003-11-14Martin Stjernholm  */
d689592008-07-09Martin Stjernholm #define MATCH_IS_WIDE(X) #define INPUT_IS_WIDE(X)
c6c01a2003-11-14Martin Stjernholm  MKREADSET(0) MK_VERY_LOW_SSCANF(0,0)
d689592008-07-09Martin Stjernholm #undef INPUT_IS_WIDE #define INPUT_IS_WIDE(X) X
c6c01a2003-11-14Martin Stjernholm  MK_VERY_LOW_SSCANF(1,0) MK_VERY_LOW_SSCANF(2,0)
d689592008-07-09Martin Stjernholm #undef MATCH_IS_WIDE #define MATCH_IS_WIDE(X) X
c6c01a2003-11-14Martin Stjernholm  MKREADSET(1) MKREADSET(2)
d689592008-07-09Martin Stjernholm #undef INPUT_IS_WIDE #define INPUT_IS_WIDE(X)
c6c01a2003-11-14Martin Stjernholm  MK_VERY_LOW_SSCANF(0,1) MK_VERY_LOW_SSCANF(0,2)
d689592008-07-09Martin Stjernholm #undef INPUT_IS_WIDE #define INPUT_IS_WIDE(X) X
c6c01a2003-11-14Martin Stjernholm  MK_VERY_LOW_SSCANF(1,1) MK_VERY_LOW_SSCANF(2,1) MK_VERY_LOW_SSCANF(1,2) MK_VERY_LOW_SSCANF(2,2)
9a2ff02014-08-28Per Hedbor  /* */ INT32 low_sscanf_pcharp(PCHARP input, ptrdiff_t len, PCHARP format, ptrdiff_t format_len,
558e912014-10-05Martin Nilsson  ptrdiff_t *chars_matched)
9a2ff02014-08-28Per Hedbor { int ok; check_c_stack(sizeof(struct sscanf_set)*2 + 512); switch( input.shift*3 + format.shift ) { case 0: return very_low_sscanf_0_0(input.ptr, len,format.ptr, format_len,
11ff452015-08-24Per Hedbor  chars_matched, &ok,0);
9a2ff02014-08-28Per Hedbor  case 1: return very_low_sscanf_0_1(input.ptr, len, format.ptr, format_len,
11ff452015-08-24Per Hedbor  chars_matched, &ok,0);
9a2ff02014-08-28Per Hedbor  case 2: return very_low_sscanf_0_2(input.ptr, len, format.ptr, format_len,
11ff452015-08-24Per Hedbor  chars_matched, &ok,0);
9a2ff02014-08-28Per Hedbor  case 3: return very_low_sscanf_1_0(input.ptr, len, format.ptr, format_len,
11ff452015-08-24Per Hedbor  chars_matched, &ok,0);
9a2ff02014-08-28Per Hedbor  case 4: return very_low_sscanf_1_1(input.ptr, len, format.ptr, format_len,
11ff452015-08-24Per Hedbor  chars_matched, &ok,0);
9a2ff02014-08-28Per Hedbor  case 5: return very_low_sscanf_1_2(input.ptr, len, format.ptr, format_len,
11ff452015-08-24Per Hedbor  chars_matched, &ok,0);
9a2ff02014-08-28Per Hedbor  case 6: return very_low_sscanf_2_0(input.ptr, len, format.ptr, format_len,
11ff452015-08-24Per Hedbor  chars_matched, &ok,0);
9a2ff02014-08-28Per Hedbor  case 7: return very_low_sscanf_2_1(input.ptr, len, format.ptr, format_len,
11ff452015-08-24Per Hedbor  chars_matched, &ok,0);
9a2ff02014-08-28Per Hedbor  case 8: return very_low_sscanf_2_2(input.ptr, len, format.ptr, format_len,
11ff452015-08-24Per Hedbor  chars_matched, &ok,0);
9a2ff02014-08-28Per Hedbor  }
5ee9e32018-12-26Henrik Grubbström (Grubba)  UNREACHABLE(return 0);
9a2ff02014-08-28Per Hedbor }
c6c01a2003-11-14Martin Stjernholm /* Simplified interface to very_low_sscanf_{0,1,2}_{0,1,2}(). */
558e912014-10-05Martin Nilsson INT32 low_sscanf(struct pike_string *data, struct pike_string *format)
c6c01a2003-11-14Martin Stjernholm { ptrdiff_t matched_chars; int x; check_c_stack(sizeof(struct sscanf_set)*2 + 512); switch(data->size_shift*3 + format->size_shift) { /* input_shift : match_shift */ case 0: /* 0 : 0 */
759c422015-10-17Martin Nilsson  return very_low_sscanf_0_0(STR0(data), data->len, STR0(format), format->len, &matched_chars, &x,data);
c6c01a2003-11-14Martin Stjernholm  break; case 1: /* 0 : 1 */
759c422015-10-17Martin Nilsson  return very_low_sscanf_0_1(STR0(data), data->len, STR1(format), format->len, &matched_chars, &x,data);
c6c01a2003-11-14Martin Stjernholm  break; case 2: /* 0 : 2 */
759c422015-10-17Martin Nilsson  return very_low_sscanf_0_2(STR0(data), data->len, STR2(format), format->len, &matched_chars, &x,data);
c6c01a2003-11-14Martin Stjernholm  break; case 3: /* 1 : 0 */
759c422015-10-17Martin Nilsson  return very_low_sscanf_1_0(STR1(data), data->len, STR0(format), format->len, &matched_chars, &x,data);
c6c01a2003-11-14Martin Stjernholm  break; case 4: /* 1 : 1 */
759c422015-10-17Martin Nilsson  return very_low_sscanf_1_1(STR1(data), data->len, STR1(format), format->len, &matched_chars, &x,data);
c6c01a2003-11-14Martin Stjernholm  break; case 5: /* 1 : 2 */
759c422015-10-17Martin Nilsson  return very_low_sscanf_1_2(STR1(data), data->len, STR2(format), format->len, &matched_chars, &x,data);
c6c01a2003-11-14Martin Stjernholm  break; case 6: /* 2 : 0 */
759c422015-10-17Martin Nilsson  return very_low_sscanf_2_0(STR2(data), data->len, STR0(format), format->len, &matched_chars, &x,data);
c6c01a2003-11-14Martin Stjernholm  break; case 7: /* 2 : 1 */
759c422015-10-17Martin Nilsson  return very_low_sscanf_2_1(STR2(data), data->len, STR1(format), format->len, &matched_chars, &x,data);
c6c01a2003-11-14Martin Stjernholm  break; case 8: /* 2 : 2 */
759c422015-10-17Martin Nilsson  return very_low_sscanf_2_2(STR2(data), data->len, STR2(format), format->len, &matched_chars, &x,data);
c6c01a2003-11-14Martin Stjernholm  break; }
759c422015-10-17Martin Nilsson 
5ee9e32018-12-26Henrik Grubbström (Grubba)  UNREACHABLE(return 0);
c6c01a2003-11-14Martin Stjernholm } /*! @decl int sscanf(string data, string format, mixed ... lvalues) *! *! The purpose of sscanf is to match a string @[data] against a @[format] *! string and place the matching results into a list of variables. The list *! of @[lvalues] are destructively modified (which is only possible because
4869472016-11-17Henrik Grubbström (Grubba)  *! sscanf really is a special form, rather than a pike function) with the values
c6c01a2003-11-14Martin Stjernholm  *! extracted from the @[data] according to the @[format] specification. Only *! the variables up to the last matching directive of the format string are *! touched. *!
4869472016-11-17Henrik Grubbström (Grubba)  *! The @[format] string may contain strings separated by special matching
c6c01a2003-11-14Martin Stjernholm  *! directives like @tt{%d@}, @tt{%s@} @tt{%c@} and @tt{%f@}. Every such
4869472016-11-17Henrik Grubbström (Grubba)  *! directive corresponds to one of the @[lvalues], in the order they are listed.
c6c01a2003-11-14Martin Stjernholm  *! An lvalue is the name of a variable, a name of a local variable, an index
4869472016-11-17Henrik Grubbström (Grubba)  *! into an array, mapping or object. It is because of these lvalues that sscanf
c6c01a2003-11-14Martin Stjernholm  *! can not be implemented as a normal function. *! *! Whenever a percent character is found in the format string, a match is *! performed, according to which operator and modifiers follow it: *! *! @string *! @value "%b"
68ab582004-03-23Martin Nilsson  *! Reads a binary integer (@expr{"0101"@} makes @expr{5@})
c6c01a2003-11-14Martin Stjernholm  *! @value "%d"
68ab582004-03-23Martin Nilsson  *! Reads a decimal integer (@expr{"0101"@} makes @expr{101@}).
c6c01a2003-11-14Martin Stjernholm  *! @value "%o"
68ab582004-03-23Martin Nilsson  *! Reads an octal integer (@expr{"0101"@} makes @expr{65@}).
c6c01a2003-11-14Martin Stjernholm  *! @value "%x"
68ab582004-03-23Martin Nilsson  *! Reads a hexadecimal integer (@expr{"0101"@} makes @expr{257@}).
c6c01a2003-11-14Martin Stjernholm  *! @value "%D" *! Reads an integer that is either octal (leading zero),
4869472016-11-17Henrik Grubbström (Grubba)  *! hexadecimal (leading @expr{0x@}) or decimal. (@expr{"0101"@} makes
68ab582004-03-23Martin Nilsson  *! @expr{65@}).
c6c01a2003-11-14Martin Stjernholm  *! @value "%c" *! Reads one character and returns it as an integer
68ab582004-03-23Martin Nilsson  *! (@expr{"0101"@} makes @expr{48@}, or @expr{'0'@}, leaving *! @expr{"101"@} for later directives). Using the field width and *! endianness modifiers, you can decode integers of any size and *! endianness. For example @expr{"%-2c"@} decodes @expr{"0101"@}
4869472016-11-17Henrik Grubbström (Grubba)  *! into @expr{12592@}, leaving @expr{"01"@} for later directives.
68ab582004-03-23Martin Nilsson  *! The sign modifiers can be used to modify the signature of the *! data, making @expr{"%+1c"@} decode @expr{"ä"@} into *! @expr{-28@}.
a1c9d72010-11-19Henrik Grubbström (Grubba)  *! @value "%n" *! Returns the current character offset in @[data].
e02b4f2010-11-21Henrik Grubbström (Grubba)  *! Note that any characters matching fields scanned with the *! @expr{"!"@}-modifier are removed from the count (see below).
c6c01a2003-11-14Martin Stjernholm  *! @value "%f" *! Reads a float ("0101" makes 101.0). *! @value "%F"
68ab582004-03-23Martin Nilsson  *! Reads a float encoded according to the IEEE single precision *! binary format (@expr{"0101"@} makes @expr{6.45e-10@}, *! approximately). Given a field width modifier of 8 (4 is the *! default), the data will be decoded according to the IEEE *! double precision binary format instead. (You will however *! still get a float, unless your pike was compiled with the *! configure argument @tt{--with-double-precision@}.)
c6c01a2003-11-14Martin Stjernholm  *! @value "%s" *! Reads a string. If followed by %d, %s will only read non-numerical *! characters. If followed by a %[], %s will only read characters not *! present in the set. If followed by normal text, %s will match all *! characters up to but not including the first occurrence of that text.
e37f182007-04-29Martin Nilsson  *! @value "%H"
f424972007-04-30Henrik Grubbström (Grubba)  *! Reads a Hollerith-encoded string, i.e. first reads the length
e37f182007-04-29Martin Nilsson  *! of the string and then that number of characters. The size and *! byte order of the length descriptor can be modified in the *! same way as @tt{%c@}. As an example @expr{"%2H"@} first reads *! @expr{"%2c"@} and then the resulting number of characters.
c6c01a2003-11-14Martin Stjernholm  *! @value "%[set]" *! Matches a string containing a given set of characters (those given
dc8c3e2008-05-14Marcus Comstedt  *! inside the brackets). Ranges of characters can be defined by using *! a minus character between the first and the last character to be
4869472016-11-17Henrik Grubbström (Grubba)  *! included in the range. Example: @expr{%[0-9H]@} means any number or 'H'.
dc8c3e2008-05-14Marcus Comstedt  *! Note that sets that includes the character '-' must have it first *! (not possible in complemented sets, see below) or last in the brackets *! to avoid having a range defined. Sets including the character ']' must
65493f2005-09-01Martin Stjernholm  *! list this first too. If both '-' and ']' should be included
dc8c3e2008-05-14Marcus Comstedt  *! then put ']' first and '-' last. It is not possible to make a range *! that ends with ']'; make the range end with '\' instead and put ']' *! at the beginning of the set. Likewise it is generally not possible *! to have a range start with '-'; make the range start with '.' instead *! and put '-' at the end of the set. If the first character after the *! [ bracket is '^' (%[^set]), and this character does not begin a *! range, it means that the set is complemented, which is to say that *! any character except those inside brackets is matched. To include '-' *! in a complemented set, it must be put last, not first. To include '^' *! in a non-complemented set, it can be put anywhere but first, or be *! specified as a range ("^-^").
c6c01a2003-11-14Martin Stjernholm  *! @value "%{format%}" *! Repeatedly matches 'format' as many times as possible and assigns an *! array of arrays with the results to the lvalue. *! @value "%O" *! Match a Pike constant, such as string or integer (currently only *! integer, string and character constants are functional). *! @value "%%" *! Match a single percent character (hence this is how you quote the % *! character to just match, and not start an lvalue matcher directive). *! @endstring *! *! Similar to @[sprintf], you may supply modifiers between the % character *! and the operator, to slightly change its behaviour from the default: *! *! @string *! @value "*" *! The operator will only match its argument, without assigning any *! variable. *! @value number
68ab582004-03-23Martin Nilsson  *! You may define a field width by supplying a numeric modifier. *! This means that the format should match that number of *! characters in the input data; be it a @i{number@} characters *! long string, integer or otherwise (@expr{"0101"@} using the *! format %2c would read an unsigned short @expr{12337@}, leaving *! the final @expr{"01"@} for later operators, for instance).
c6c01a2003-11-14Martin Stjernholm  *! @value "-" *! Supplying a minus sign toggles the decoding to read the data encoded *! in little-endian byte order, rather than the default network *! (big-endian) byte order. *! @value "+"
68ab582004-03-23Martin Nilsson  *! Interpret the data as a signed entity. In other words, *! @expr{"%+1c"@} will read @expr{"\xFF"@} as @expr{-1@} instead *! of @expr{255@}, as @expr{"%1c"@} would have.
e02b4f2010-11-21Henrik Grubbström (Grubba)  *! @value "!" *! Ignore the matched characters with respect to any following *! @expr{"%n"@}.
c6c01a2003-11-14Martin Stjernholm  *! @endstring *! *! @note *! Sscanf does not use backtracking. Sscanf simply looks at the format string *! up to the next % and tries to match that with the string. It then proceeds *! to look at the next part. If a part does not match, sscanf immediately *! returns how many % were matched. If this happens, the lvalues for % that *! were not matched will not be changed. *! *! @example
4869472016-11-17Henrik Grubbström (Grubba)  *! @code
c6c01a2003-11-14Martin Stjernholm  *! // a will be assigned "oo" and 1 will be returned *! sscanf("foo", "f%s", a); *! *! // a will be 4711 and b will be "bar", 2 will be returned *! sscanf("4711bar", "%d%s", a, b); *! *! // a will be 4711, 2 will be returned *! sscanf("bar4711foo", "%*s%d", a); *! *! // a will become "test", 2 will be returned *! sscanf(" \t test", "%*[ \t]%s", a); *! *! // Remove "the " from the beginning of a string *! // If 'str' does not begin with "the " it will not be changed *! sscanf(str, "the %s", str); *! *! // It is also possible to declare a variable directly in the sscanf call; *! // another reason for sscanf not to be an ordinary function: *! *! sscanf("abc def", "%s %s", string a, string b);
4869472016-11-17Henrik Grubbström (Grubba)  *! @endcode
c6c01a2003-11-14Martin Stjernholm  *! *! @returns *! The number of directives matched in the format string. Note that a string *! directive (%s or %[]) counts as a match even when matching just the empty *! string (which either may do). *! @seealso *! @[sprintf], @[array_sscanf] * @[parse_format] */
fffdad2014-10-13Martin Nilsson void o_sscanf(INT32 args)
c6c01a2003-11-14Martin Stjernholm { INT32 i=0; int x;
19961b2017-04-08Martin Nilsson  struct svalue *save_sp=Pike_sp;
c6c01a2003-11-14Martin Stjernholm 
19961b2017-04-08Martin Nilsson  if(TYPEOF(Pike_sp[-args]) != T_STRING)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("sscanf", 1, "string");
c6c01a2003-11-14Martin Stjernholm 
19961b2017-04-08Martin Nilsson  if(TYPEOF(Pike_sp[1-args]) != T_STRING)
f982742016-01-26Martin Nilsson  SIMPLE_ARG_TYPE_ERROR("sscanf", 2, "string");
c6c01a2003-11-14Martin Stjernholm 
19961b2017-04-08Martin Nilsson  i = low_sscanf(Pike_sp[-args].u.string, Pike_sp[1-args].u.string);
c6c01a2003-11-14Martin Stjernholm 
19961b2017-04-08Martin Nilsson  if(Pike_sp-save_sp > args/2-1)
c6c01a2003-11-14Martin Stjernholm  Pike_error("Too few arguments for sscanf format.\n");
19961b2017-04-08Martin Nilsson  for(x=0;x<Pike_sp-save_sp;x++)
c6c01a2003-11-14Martin Stjernholm  assign_lvalue(save_sp-args+2+x*2,save_sp+x);
19961b2017-04-08Martin Nilsson  pop_n_elems(Pike_sp-save_sp +args);
c6c01a2003-11-14Martin Stjernholm  #ifdef PIKE_DEBUG if(Pike_interpreter.trace_level >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); } /*! @decl array array_sscanf(string data, string format) *! *! This function works just like @[sscanf()], but returns the matched *! results in an array instead of assigning them to lvalues. This is often *! useful for user-defined sscanf strings. *! *! @seealso *! @[sscanf()], @[`/()] */ PMOD_EXPORT void f_sscanf(INT32 args) { INT32 i;
19961b2017-04-08Martin Nilsson  struct svalue *save_sp=Pike_sp;
c6c01a2003-11-14Martin Stjernholm  struct array *a; check_all_args("array_sscanf",args,BIT_STRING, BIT_STRING,0);
19961b2017-04-08Martin Nilsson  i = low_sscanf(Pike_sp[-args].u.string, Pike_sp[1-args].u.string);
37e4132008-05-17Marcus Comstedt 
19961b2017-04-08Martin Nilsson  a = aggregate_array(Pike_sp - save_sp);
37e4132008-05-17Marcus Comstedt  pop_n_elems(args); push_array(a); }
6f16cb2008-05-18Henrik Grubbström (Grubba) static void push_sscanf_argument_types(PCHARP format, ptrdiff_t format_len,
558e912014-10-05Martin Nilsson  int cnt)
6f16cb2008-05-18Henrik Grubbström (Grubba) { for(; cnt < format_len; cnt++) { int no_assign=0; while((cnt<format_len) && (INDEX_PCHARP(format, cnt) != '%')) cnt++; cnt++; if (cnt >= format_len) break; while(1) { switch(INDEX_PCHARP(format, cnt)) { case '%': break; case '*': no_assign=1;
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
6f16cb2008-05-18Henrik Grubbström (Grubba)  case '-': case '+':
e02b4f2010-11-21Henrik Grubbström (Grubba)  case '!':
6f16cb2008-05-18Henrik Grubbström (Grubba)  case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': cnt++;
39ff2d2008-05-18Henrik Grubbström (Grubba)  if(cnt>=format_len) {
94d66b2008-05-24Henrik Grubbström (Grubba)  yyreport(REPORT_ERROR, type_check_system_string, 0, "Error in sscanf format string.");
39ff2d2008-05-18Henrik Grubbström (Grubba)  break; }
6f16cb2008-05-18Henrik Grubbström (Grubba)  continue; case '{': { int e; int depth = 1; for(e=cnt+1;depth;e++) { if(e>=format_len) {
94d66b2008-05-24Henrik Grubbström (Grubba)  yyreport(REPORT_ERROR, type_check_system_string, 0, "Missing %%} in format string.");
6f16cb2008-05-18Henrik Grubbström (Grubba)  break; } if(INDEX_PCHARP(format, e)=='%') { switch(INDEX_PCHARP(format, e+1)) { case '%': e++; break; case '}': depth--; break; case '{': depth++; break; } } } if (!no_assign) { type_stack_mark();
558e912014-10-05Martin Nilsson  push_sscanf_argument_types(format, e, cnt+1);
39ff2d2008-05-18Henrik Grubbström (Grubba)  if (!(depth = pop_stack_mark())) { push_type(PIKE_T_ZERO); } else { /* Join the argument types. */
4872862008-06-18Henrik Grubbström (Grubba)  while (depth > 1) {
39ff2d2008-05-18Henrik Grubbström (Grubba)  push_type(T_OR); depth--; }
6f16cb2008-05-18Henrik Grubbström (Grubba)  }
04017d2020-01-02Henrik Grubbström (Grubba)  push_unlimited_array_type(PIKE_T_ARRAY); push_unlimited_array_type(PIKE_T_ARRAY);
6f16cb2008-05-18Henrik Grubbström (Grubba)  }
d81c312008-05-18Henrik Grubbström (Grubba)  cnt = e;
6f16cb2008-05-18Henrik Grubbström (Grubba)  break; }
120fff2020-08-07Henrik Grubbström (Grubba)  case 'n': /* FIXME: tIntPos? */
6f16cb2008-05-18Henrik Grubbström (Grubba)  case 'b': case 'o': case 'd': case 'x': case 'D': case 'i':
120fff2020-08-07Henrik Grubbström (Grubba)  case 'c': /* FIXME: Use the width of the input string. */
6f16cb2008-05-18Henrik Grubbström (Grubba)  if (!no_assign) push_finished_type(int_type_string); break; case '[': { int ch; cnt++; if (cnt >= format_len) {
94d66b2008-05-24Henrik Grubbström (Grubba)  yyreport(REPORT_ERROR, type_check_system_string, 0, "Error in sscanf format string.");
6f16cb2008-05-18Henrik Grubbström (Grubba)  break; } if((INDEX_PCHARP(format, cnt)=='^') && (cnt+2>=format_len || (INDEX_PCHARP(format, cnt+1)!='-') ||
c9562b2014-10-05Martin Nilsson  (INDEX_PCHARP(format, cnt+2)==']') ))
6f16cb2008-05-18Henrik Grubbström (Grubba)  { cnt++;
39ff2d2008-05-18Henrik Grubbström (Grubba)  if(cnt >= format_len) {
94d66b2008-05-24Henrik Grubbström (Grubba)  yyreport(REPORT_ERROR, type_check_system_string, 0, "Error in sscanf format string.");
39ff2d2008-05-18Henrik Grubbström (Grubba)  break; }
6f16cb2008-05-18Henrik Grubbström (Grubba)  } if(((ch = INDEX_PCHARP(format, cnt))==']') || (ch=='-')) { cnt++;
39ff2d2008-05-18Henrik Grubbström (Grubba)  if(cnt >= format_len) {
94d66b2008-05-24Henrik Grubbström (Grubba)  yyreport(REPORT_ERROR, type_check_system_string, 0, "Error in sscanf format string.");
39ff2d2008-05-18Henrik Grubbström (Grubba)  break; }
6f16cb2008-05-18Henrik Grubbström (Grubba)  ch = INDEX_PCHARP(format, cnt); } while(ch != ']') { if(ch == '-') { cnt++;
39ff2d2008-05-18Henrik Grubbström (Grubba)  if(cnt >= format_len) {
94d66b2008-05-24Henrik Grubbström (Grubba)  yyreport(REPORT_ERROR, type_check_system_string, 0, "Error in sscanf format string.");
39ff2d2008-05-18Henrik Grubbström (Grubba)  break; }
6f16cb2008-05-18Henrik Grubbström (Grubba)  if(INDEX_PCHARP(format, cnt)==']') { break; } } cnt++;
39ff2d2008-05-18Henrik Grubbström (Grubba)  if(cnt>=format_len) {
94d66b2008-05-24Henrik Grubbström (Grubba)  yyreport(REPORT_ERROR, type_check_system_string, 0, "Error in sscanf format string.");
39ff2d2008-05-18Henrik Grubbström (Grubba)  break; }
6f16cb2008-05-18Henrik Grubbström (Grubba)  ch = INDEX_PCHARP(format, cnt); } }
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
6f16cb2008-05-18Henrik Grubbström (Grubba)  case 's': case 'H':
120fff2020-08-07Henrik Grubbström (Grubba)  if (!no_assign) { /* FIXME: Use the type of the input string. */
6f16cb2008-05-18Henrik Grubbström (Grubba)  push_finished_type(string_type_string);
120fff2020-08-07Henrik Grubbström (Grubba)  }
6f16cb2008-05-18Henrik Grubbström (Grubba)  break; case 'F': case 'f': if (!no_assign) push_finished_type(float_type_string); break; break; case 'O': if (!no_assign) push_finished_type(mixed_type_string); break; default:
94d66b2008-05-24Henrik Grubbström (Grubba)  yyreport(REPORT_ERROR, type_check_system_string, 0, "Unknown sscanf token %%%c(0x%02x) at offset %d.",
2ffe972008-05-21Henrik Grubbström (Grubba)  INDEX_PCHARP(format, cnt), INDEX_PCHARP(format, cnt), cnt-1);
39ff2d2008-05-18Henrik Grubbström (Grubba)  break;
6f16cb2008-05-18Henrik Grubbström (Grubba)  } break; } } } void f___handle_sscanf_format(INT32 args) { struct pike_type *res; struct pike_type *tmp; struct pike_string *attr; struct pike_string *fmt; struct pike_string *sscanf_format_string; struct pike_string *sscanf_76_format_string; int found = 0; int fmt_count;
2ffe972008-05-21Henrik Grubbström (Grubba) 
6f16cb2008-05-18Henrik Grubbström (Grubba) #if 0
120fff2020-08-07Henrik Grubbström (Grubba)  fprintf(stderr, "__handle_sscanf_format()\n");
6f16cb2008-05-18Henrik Grubbström (Grubba) #endif /* 0 */ if (args != 4) SIMPLE_WRONG_NUM_ARGS_ERROR("__handle_sscanf_format", 4);
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-4]) != PIKE_T_STRING)
6f16cb2008-05-18Henrik Grubbström (Grubba)  SIMPLE_ARG_TYPE_ERROR("__handle_sscanf_format", 1, "string");
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-3]) != PIKE_T_STRING)
6f16cb2008-05-18Henrik Grubbström (Grubba)  SIMPLE_ARG_TYPE_ERROR("__handle_sscanf_format", 2, "string");
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-2]) != PIKE_T_TYPE)
6f16cb2008-05-18Henrik Grubbström (Grubba)  SIMPLE_ARG_TYPE_ERROR("__handle_sscanf_format", 3, "type");
017b572011-10-28Henrik Grubbström (Grubba)  if (TYPEOF(Pike_sp[-1]) != PIKE_T_TYPE)
6f16cb2008-05-18Henrik Grubbström (Grubba)  SIMPLE_ARG_TYPE_ERROR("__handle_sscanf_format", 4, "type"); tmp = Pike_sp[-1].u.type; if ((tmp->type != PIKE_T_FUNCTION) && (tmp->type != T_MANY)) { SIMPLE_ARG_TYPE_ERROR("__handle_sscanf_format", 4, "type(function)"); }
13670c2015-05-25Martin Nilsson  MAKE_CONST_STRING(sscanf_format_string, "sscanf_format"); MAKE_CONST_STRING(sscanf_76_format_string, "sscanf_76_format");
6f16cb2008-05-18Henrik Grubbström (Grubba)  if (Pike_sp[-4].u.string != sscanf_format_string) { if (Pike_sp[-4].u.string != sscanf_76_format_string) { pop_n_elems(args); push_undefined(); return; } } fmt = Pike_sp[-3].u.string;
13670c2015-05-25Martin Nilsson  MAKE_CONST_STRING(attr, "sscanf_args");
6f16cb2008-05-18Henrik Grubbström (Grubba) 
4872862008-06-18Henrik Grubbström (Grubba) #if 0 fprintf(stderr, "Checking sscanf format: \"%s\": ", fmt->str); simple_describe_type(Pike_sp[-1].u.type); fprintf(stderr, "\n"); #endif /* 0 */
6f16cb2008-05-18Henrik Grubbström (Grubba)  type_stack_mark(); type_stack_mark(); for (; tmp; tmp = tmp->cdr) { struct pike_type *arg = tmp->car; int array_cnt = 0; while(arg) { switch(arg->type) { case PIKE_T_ATTRIBUTE: if (arg->car == (struct pike_type *)attr) break;
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
6f16cb2008-05-18Henrik Grubbström (Grubba)  case PIKE_T_NAME: arg = arg->cdr; continue; case PIKE_T_ARRAY: array_cnt++;
2978662019-12-17Henrik Grubbström (Grubba)  arg = arg->cdr;
6f16cb2008-05-18Henrik Grubbström (Grubba)  continue; default: arg = NULL; break; } break; } if (arg) { type_stack_mark(); push_sscanf_argument_types(MKPCHARP(fmt->str, fmt->size_shift),
558e912014-10-05Martin Nilsson  fmt->len, 0);
6f16cb2008-05-18Henrik Grubbström (Grubba)  if (!array_cnt) { pop_stack_mark(); push_type(T_VOID); /* No more args */ while (tmp->type == PIKE_T_FUNCTION) { tmp = tmp->cdr; } push_finished_type(tmp->cdr); /* return type */ push_reverse_type(T_MANY); fmt_count = pop_stack_mark(); while (fmt_count > 1) { push_reverse_type(T_FUNCTION); fmt_count--; } res = pop_unfinished_type(); pop_n_elems(args); push_type_value(res);
4872862008-06-18Henrik Grubbström (Grubba) #if 0 fprintf(stderr, " ==> "); simple_describe_type(res); fprintf(stderr, "\n"); #endif /* 0 */
6f16cb2008-05-18Henrik Grubbström (Grubba)  return; } else {
39ff2d2008-05-18Henrik Grubbström (Grubba)  if (!(fmt_count = pop_stack_mark())) { push_type(PIKE_T_ZERO); } else { /* Join the argument types into the array. */
4872862008-06-18Henrik Grubbström (Grubba)  while (fmt_count > 1) {
39ff2d2008-05-18Henrik Grubbström (Grubba)  push_type(T_OR); fmt_count--; }
6f16cb2008-05-18Henrik Grubbström (Grubba)  } while (array_cnt--) {
04017d2020-01-02Henrik Grubbström (Grubba)  push_unlimited_array_type(PIKE_T_ARRAY);
6f16cb2008-05-18Henrik Grubbström (Grubba)  } found = 1; } } else { push_finished_type(tmp->car); } if (tmp->type == T_MANY) { /* Get the return type. */ tmp = tmp->cdr; break; } } if (found) { /* Found, but inside an array, so we need to build the function * type here. */ push_finished_type(tmp); /* Return type. */ push_reverse_type(T_MANY); fmt_count = pop_stack_mark(); while (fmt_count > 1) { push_reverse_type(T_FUNCTION); fmt_count--; } res = pop_unfinished_type(); pop_n_elems(args); push_type_value(res);
4872862008-06-18Henrik Grubbström (Grubba) #if 0 fprintf(stderr, " ==> "); simple_describe_type(res); fprintf(stderr, "\n"); #endif /* 0 */
2ffe972008-05-21Henrik Grubbström (Grubba)  return;
6f16cb2008-05-18Henrik Grubbström (Grubba)  } else if (tmp) { /* Check if it's in the return type. */ struct pike_type *arg = tmp; int array_cnt = 0; while(arg) { switch(arg->type) { case PIKE_T_ATTRIBUTE: if (arg->car == (struct pike_type *)attr) break;
5f50842018-02-12Marcus Comstedt  /* FALLTHRU */
6f16cb2008-05-18Henrik Grubbström (Grubba)  case PIKE_T_NAME: arg = arg->cdr; continue; case PIKE_T_ARRAY: array_cnt++;
2978662019-12-17Henrik Grubbström (Grubba)  arg = arg->cdr;
6f16cb2008-05-18Henrik Grubbström (Grubba)  continue; default: arg = NULL; break; } break; } if (arg) { type_stack_mark(); push_sscanf_argument_types(MKPCHARP(fmt->str, fmt->size_shift),
558e912014-10-05Martin Nilsson  fmt->len, 0);
6f16cb2008-05-18Henrik Grubbström (Grubba)  /* Join the argument types. */
3177592008-05-19Henrik Grubbström (Grubba)  if (!(fmt_count = pop_stack_mark())) { push_type(PIKE_T_ZERO); } else while (fmt_count > 2) {
6f16cb2008-05-18Henrik Grubbström (Grubba)  push_type(T_OR);
3177592008-05-19Henrik Grubbström (Grubba)  fmt_count--;
6f16cb2008-05-18Henrik Grubbström (Grubba)  } while (array_cnt--) {
04017d2020-01-02Henrik Grubbström (Grubba)  push_unlimited_array_type(PIKE_T_ARRAY);
6f16cb2008-05-18Henrik Grubbström (Grubba)  } /* Rebuild the function type backwards. */ push_reverse_type(T_MANY); fmt_count = pop_stack_mark(); while (fmt_count > 1) { push_reverse_type(T_FUNCTION); fmt_count--; } res = pop_unfinished_type(); pop_n_elems(args); push_type_value(res);
4872862008-06-18Henrik Grubbström (Grubba) #if 0 fprintf(stderr, " ==> "); simple_describe_type(res); fprintf(stderr, "\n"); #endif /* 0 */
6f16cb2008-05-18Henrik Grubbström (Grubba)  return; } } /* No marker found. */ #if 0 fprintf(stderr, " ==> No marker found.\n"); #endif /* 0 */ pop_stack_mark(); type_stack_pop_to_mark(); pop_n_elems(args); push_undefined(); }