pike.git / src / builtin.cmod

version» Context lines:

pike.git/src/builtin.cmod:21:   #include "threads.h"   #include "module_support.h"   #include "cyclic.h"   #include "bignum.h"   #include "main.h"   #include "operators.h"   #include "builtin_functions.h"   #include "fsort.h"   #include "port.h"   #include "gc.h" - #include "block_alloc.h" + #include "block_allocator.h"   #include "pikecode.h"   #include "opcodes.h"      #include <ctype.h>   #include <errno.h>   #include <math.h>      DECLARATIONS    -  +  + /*! @module System +  */ +  + #if defined(HAVE_MKTIME) && defined(HAVE_GMTIME) && defined(HAVE_LOCALTIME) + PIKECLASS TM + /*! @class TM +  *! A wrapper for the system struct tm time keeping structure. +  *! This can be used as a (very) lightweight alternative to Calendar. +  */ + { +  CVAR struct tm t; +  CVAR time_t unix_time; +  CVAR int modified; +  CVAR struct pike_string *set_zone; +  + #ifdef STRUCT_TM_HAS___TM_GMTOFF + #define tm_zone __tm_zone + #define tm_gmtoff __tm_gmtoff + #endif +  + #if 0 + /* This is supposed to make any timezone work. +  * However: It does not really work. And makes things even slower than +  * the calendar module. +  */ + #ifndef HAVE_EXTERNAL_TIMEZONE + #define timezone 0 + #endif + #define WITH_ZONE(RETURNTYPE, FUNCTION, ARGUMENTS, CALL ) \ +  static RETURNTYPE FUNCTION##_zone ARGUMENTS \ +  { \ +  RETURNTYPE res; \ +  int reset = 0; \ +  char *old_zone = NULL; \ +  if( x->tm_zone ) \ +  { \ +  reset = 1; \ +  old_zone = getenv("TZ"); \ +  setenv("TZ", x->tm_zone, 1 ); \ +  tzset(); \ +  x->tm_gmtoff = timezone; \ +  } \ +  \ +  res = FUNCTION CALL; \ +  \ +  if( reset ) \ +  { \ +  if( old_zone ) \ +  setenv("TZ", old_zone, 1 ); \ +  else \ +  unsetenv( "TZ" ); \ +  tzset(); \ +  } \ +  return res; \ +  } +  +  WITH_ZONE(time_t,mktime,( struct tm *x ),(x)); +  WITH_ZONE(struct tm*,localtime,( time_t *t, struct tm *x ),(t)); +  WITH_ZONE(char *,asctime,( struct tm *x ),(x)); +  WITH_ZONE(int,strftime,( char *buffer, size_t max_len, char *format, struct tm *x ),(buffer,max_len,format,x)); + #ifdef HAVE_STRPTIME +  WITH_ZONE(char *,strptime,( const char *str, const char *format, struct tm *x ),(str,format,x)); + #endif + #else + #define strftime_zone strftime + #define mktime_zone mktime + #define strptime_zone strptime + #define asctime_zone asctime + #define localtime_zone(X,Y) localtime(X) + #endif + #ifndef HAVE_EXTERNAL_TIMEZONE + #undef timezone + #endif +  + #define MODIFY(X) do{ THIS->modified = 1;THIS->t.X; }while(0) + #define FIX_THIS() do { \ +  if(THIS->modified){ \ +  THIS->unix_time = mktime_zone( &THIS->t ); \ +  THIS->modified = 0; \ +  } \ +  } while(0) +  + #ifdef HAVE_STRPTIME +  /* +  *! @decl int(0..1) strptime( string(1..255) format, string(1..255) data ) +  *! +  *! Parse the given @[data] using the format in @[format] as a date. +  *! +  *! %% The % character. +  *! +  *! %a or %A +  *! The weekday name according to the C locale, in abbreviated +  *! form or the full name. +  *! +  *! %b or %B or %h +  *! The month name according to the C locale, in abbreviated form +  *! or the full name. +  *! +  *! %c The date and time representation for the C locale. +  *! +  *! %C The century number (0-99). +  *! +  *! %d or %e +  *! The day of month (1-31). +  *! +  *! %D Equivalent to %m/%d/%y. +  *! +  *! %H The hour (0-23). +  *! +  *! %I The hour on a 12-hour clock (1-12). +  *! +  *! %j The day number in the year (1-366). +  *! +  *! %m The month number (1-12). +  *! +  *! %M The minute (0-59). +  *! +  *! %n Arbitrary whitespace. +  *! +  *! %p The C locale's equivalent of AM or PM. +  *! +  *! %R Equivalent to %H:%M. +  *! +  *! %S The second (0-60; 60 may occur for leap seconds; earlier also 61 was allowed). +  *! +  *! %t Arbitrary whitespace. +  *! +  *! %T Equivalent to %H:%M:%S. +  *! +  *! %U The week number with Sunday the first day of the week (0-53). +  *! +  *! %w The weekday number (0-6) with Sunday = 0. +  *! +  *! %W The week number with Monday the first day of the week (0-53). +  *! +  *! %x The date, using the C locale's date format. +  *! +  *! %X The time, using the C locale's time format. +  *! +  *! %y +  *! The year within century (0-99). When a century is not +  *! otherwise specified, values in the range 69-99 refer to years +  *! in the twentieth century (1969-1999); values in the range +  *! 00-68 refer to years in the twenty-first century (2000-2068). +  *! +  *! %Y The year, including century (for example, 1991). +  *! +  */ +  PIKEFUN int(0..1) strptime( string(1..255) format, string(1..255) data ) +  { +  if( format->size_shift || data->size_shift ) +  Pike_error("Only 8bit strings are supported\n"); +  THIS->modified = 1; +  if( strptime_zone( data->str, format->str, &THIS->t ) == NULL ) +  RETURN 0; +  RETURN 1; +  } + #endif + /*! @decl string(1..255) strftime( string(1..255) format ) +  *! See also @[Gettext.setlocale] +  *! +  *! Convert the structure to a string. +  *! +  *! %a The abbreviated weekday name according to the current locale +  *! +  *! %A The full weekday name according to the current locale. +  *! +  *! %b The abbreviated month name according to the current locale. +  *! +  *! %B The full month name according to the current locale. +  *! +  *! %c The preferred date and time representation for the current locale. +  *! +  *! %C The century number (year/100) as a 2-digit integer. +  *! +  *! %d The day of the month as a decimal number (range 01 to 31). +  *! +  *! %D Equivalent to %m/%d/%y. (for Americans only. Americans should note that in other countries %d/%m/%y is rather common. This means that in international context this format is ambiguous and should not be used.) +  *! +  *! %e Like %d, the day of the month as a decimal number, but a leading zero is replaced by a space. +  *! +  *! %E Modifier: use alternative format, see below. +  *! +  *! %F Equivalent to %Y-%m-%d (the ISO 8601 date format). (C99) +  *! +  *! %G The ISO 8601 week-based year (see NOTES) with century as a decimal number. The 4-digit year corresponding to the ISO week number (see %V). This has the same format and value as %Y, except that if the ISO week number belongs to the previous or next year, that year is used instead. +  *! +  *! %g Like %G, but without century, that is, with a 2-digit year (00-99). (TZ) +  *! +  *! %h Equivalent to %b. +  *! +  *! %H The hour as a decimal number using a 24-hour clock (range 00 to 23). +  *! +  *! %I The hour as a decimal number using a 12-hour clock (range 01 to 12). +  *! +  *! %j The day of the year as a decimal number (range 001 to 366). +  *! +  *! %k The hour (24-hour clock) as a decimal number (range 0 to 23); single digits are preceded by a blank. (See also %H.) +  *! +  *! %l The hour (12-hour clock) as a decimal number (range 1 to 12); single digits are preceded by a blank. (See also %I.) +  *! +  *! %m The month as a decimal number (range 01 to 12). +  *! +  *! %M The minute as a decimal number (range 00 to 59). +  *! +  *! %n A newline character. (SU) +  *! +  *! %O Modifier: use alternative format, see below. (SU) +  *! +  *! %p Either "AM" or "PM" according to the given time value, or the corresponding strings for the current locale. Noon is treated as "PM" and midnight as "AM". +  *! +  *! %P Like %p but in lowercase: "am" or "pm" or a corresponding string for the current locale. +  *! +  *! %r The time in a.m. or p.m. notation. In the POSIX locale this is equivalent to %I:%M:%S %p. +  *! +  *! %R The time in 24-hour notation (%H:%M). (SU) For a version including the seconds, see %T below. +  *! +  *! %s The number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC). (TZ) +  *! +  *! %S The second as a decimal number (range 00 to 60). (The range is up to 60 to allow for occasional leap seconds.) +  *! +  *! %t A tab character. (SU) +  *! +  *! %T The time in 24-hour notation (%H:%M:%S). (SU) +  *! +  *! %u The day of the week as a decimal, range 1 to 7, Monday being 1. See also %w. (SU) +  *! +  *! %U The week number of the current year as a decimal number, range 00 to 53, starting with the first Sunday as the first day of week 01. See also %V and %W. +  *! +  *! %V The ISO 8601 week number of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the new year. See also %U and %W. +  *! +  *! %w The day of the week as a decimal, range 0 to 6, Sunday being 0. See also %u. +  */ +  PIKEFUN string strftime(string(1..255) format) +  { +  char *buffer = xalloc( 8192 ); +  buffer[0] = 0; +  strftime_zone( buffer, 8192, format->str, &THIS->t ); +  push_text( buffer ); +  } +  +  /* +  *! @decl int(0..60) sec; +  *! @decl int(0..59) min; +  *! @decl int(0..59) hour; +  *! @decl int(1..31) mday; +  *! @decl int(0..11) mon; +  *! @decl int year; +  *! +  *! The various fields in the structure. Note that setting these +  *! might cause other fields to be recalculated, as an example, +  *! adding 1000 to the hour field would advance the 'mday', 'mon' +  *! and possibly 'year' fields. +  *! +  *! When read the fields are always normalized. +  *! +  *! Unlike the system struct tm the 'year' field is not year-1900, +  *! instead it is the actual year. +  */ +  PIKEFUN int(0..60) `sec() { FIX_THIS();RETURN THIS->t.tm_sec; } +  PIKEFUN int(0..59) `min() { FIX_THIS();RETURN THIS->t.tm_min; } +  PIKEFUN int(0..23) `hour() { FIX_THIS();RETURN THIS->t.tm_hour; } +  PIKEFUN int(1..31) `mday() { FIX_THIS();RETURN THIS->t.tm_mday; } +  PIKEFUN int(0..11) `mon() { FIX_THIS();RETURN THIS->t.tm_mon; } +  PIKEFUN int `year() { FIX_THIS();RETURN THIS->t.tm_year+1900; } +  +  PIKEFUN int `sec=(int a) { MODIFY(tm_sec=a); } +  PIKEFUN int `min=(int a) { MODIFY(tm_min=a); } +  PIKEFUN int `hour=(int a){ MODIFY(tm_hour=a); } +  PIKEFUN int `mday=(int a){ MODIFY(tm_mday=a); } +  PIKEFUN int `year=(int a){ MODIFY(tm_year=a-1900); } +  PIKEFUN int `mon=(int a){ MODIFY(tm_mon=a); } +  +  /*! @decl int isdst +  *! +  *! True if daylight savings are in effect. If this field is -1 +  *! (the default) it (and the timezone info) will be updated +  *! automatically using the timezone rules. +  */ +  PIKEFUN int(-1..1) `isdst() { +  FIX_THIS(); +  RETURN THIS->t.tm_isdst; +  } +  +  /*! @decl int wday +  *! The day of the week, sunday is 0, saturday is 6. +  *! This is calculated from the other fields and can not be changed directly. +  */ +  PIKEFUN int(0..6) `wday() { FIX_THIS(); RETURN THIS->t.tm_wday; } +  +  /*! @decl int yday +  *! The day of the year, from 0 (the first day) to 365 +  *! This is calculated from the other fields and can not be changed directly. +  */ +  PIKEFUN int(0..365) `yday() { FIX_THIS(); RETURN THIS->t.tm_yday; } +  +  /*! @decl int unix_time() +  *! Return the unix time corresponding to this time_t. If no time +  *! can be parsed from the structure -1 is returned. +  */ +  PIKEFUN int unix_time() +  { +  FIX_THIS(); +  RETURN THIS->unix_time; +  } +  +  /*! @decl string asctime() +  *! Return a string representing the time. Mostly useful for debug +  *! purposes, the exact format is very locale (see +  *! @[Gettext.setlocale]) and OS dependent. +  */ +  PIKEFUN string asctime() +  { +  FIX_THIS(); +  { +  char *tval = asctime_zone( &THIS->t ); +  if( tval ) +  push_text( tval ); +  else +  push_text( 0 ); +  } +  } +  +  PIKEFUN void _sprintf( int flag, mapping options ) +  { +  int post_sum = 1; +  switch( flag ) +  { +  case 'O': +  push_text("System.TM("); +  post_sum = 1; +  /* fallthrough */ +  case 's': +  f_TM_asctime(0); +  push_text("\n"); +  if( THIS->t.tm_zone ) +  { +  push_text(" "); +  push_text( THIS->t.tm_zone ); +  f_add( 2 ); +  } +  else +  push_text(""); +  f_replace( 3 ); +  break; +  case 'd': +  f_TM_unix_time(0); +  break; +  default: +  Pike_error("Can not format as %c", flag ); +  } +  if( post_sum ) +  { +  push_text(")"); +  f_add(3); +  } +  +  } +  +  PIKEFUN mixed cast( string to ) +  { +  struct pike_string *s_string, *s_int; +  MAKE_CONST_STRING(s_int, "int"); +  MAKE_CONST_STRING(s_string, "string"); +  if( to == s_int ) +  { +  f_TM_unix_time(0); +  return; +  } +  if( to == s_string ) +  { +  f_TM_asctime(0); +  return; +  } +  Pike_error("Does not know how to cast to %s\n", to->str ); +  } +  +  /*! @decl string zone +  *! +  *! The timezone of this structure +  */ +  PIKEFUN string `zone() { +  FIX_THIS(); +  if( THIS->t.tm_zone ) +  push_text( THIS->t.tm_zone ); +  else +  push_undefined(); +  } +  +  /*! @decl int gmtoff +  *! The offset from GMT for the time in this tm-struct +  */ +  PIKEFUN int `gmtoff() { +  FIX_THIS(); +  push_int( THIS->t.tm_gmtoff ); +  } +  +  /* Setting the zone does not work, so.. */ +  +  /* PIKEFUN string `zone=(string x) { */ +  /* if( THIS->set_zone ) */ +  /* free_string( THIS->set_zone ); */ +  /* THIS->set_zone = x; */ +  /* MODIFY( tm_zone = x->str ); */ +  /* x->refs++; */ +  /* } */ +  +  /*! @decl int(0..1) localtime( int time ) +  *! Initialize the struct tm to the local time for the specified +  *! unix time_t. +  */ +  PIKEFUN int(0..1) localtime( int _t ) +  { +  time_t t = _t; +  struct tm *res = localtime_zone( &t, &THIS->t ); +  +  /* These are supposedly correctly by localtime_zone. */ +  res->tm_gmtoff = THIS->t.tm_gmtoff; +  res->tm_zone = THIS->t.tm_zone; +  +  if( !res ) +  RETURN 0; +  THIS->t = *res; +  THIS->modified = 1; +  RETURN 1; +  } +  +  +  /*! @decl int(0..1) gmtime( int time ) +  *! Initialize the struct tm to the UTC time for the specified +  *! unix time_t. +  */ +  PIKEFUN int(0..1) gmtime( int _t ) +  { +  time_t t = _t; +  struct tm *res = gmtime( &t ); +  +  if( !res ) +  RETURN 0; +  +  THIS->t = *res; +  THIS->modified = 1; +  RETURN 1; +  } +  +  /*! @decl void create(int t) +  *! Create a new @[TM] initialized from a unix time_t. +  *! The timezone will always be UTC when using this function. +  */ +  PIKEFUN void create( int _t ) +  { +  f_TM_gmtime( 1 ); +  if( Pike_sp[-1].u.integer == 0 ) +  Pike_error("time out of range\n"); +  } +  +  /*! @decl void create() +  *! Construct a new TM, all fields will be set to 0. +  */ +  PIKEFUN void create( ) +  { +  memset( &THIS->t, 0, sizeof( struct tm ) ); +  THIS->t.tm_isdst = -1; +  THIS->unix_time = 0; +  THIS->modified = 1; +  } +  +  /*! @decl void create( int year, int(0..11) mon, int(1..31) mday, @ +  *! int(0..24) hour, int(0..59) min, int(0..59) sec, @ +  *! string|void timezone ) +  *! Construct a new time using the given values. +  *! Slightly faster than setting them individually. +  */ +  PIKEFUN void create( int year, int(0..11) mon, int(1..31) mday, +  int(0..24) hour, int(0..59) min, int(0..59) sec, +  string|void timezone ) +  { +  struct tm *t = &THIS->t; +  t->tm_isdst = -1; +  t->tm_year = year - 1900; +  t->tm_mon = mon; +  t->tm_mday = mday; +  t->tm_hour = hour; +  t->tm_min = min; +  t->tm_sec = sec; +  if (THIS->set_zone) { +  free_string(THIS->set_zone); +  THIS->set_zone = NULL; +  } +  if( !timezone ) /* gmtime. */ +  t->tm_zone = "UTC"; +  else +  { +  add_ref(timezone); +  THIS->set_zone = timezone; +  t->tm_zone = timezone->str; +  } +  THIS->unix_time = mktime_zone( t ); +  } +  +  INIT { +  THIS->set_zone = 0; +  THIS->modified = 0; +  } +  +  EXIT { +  if( THIS->set_zone ) +  free_string( THIS->set_zone ); +  } + } + #undef FIX_THIS + #ifdef STRUCT_TM_HAS___TM_GMTOFF + #undef tm_zone + #endif + #endif + /*! @endmodule +  */ +    /*! @decl array(array(int|string|type)) describe_program(program p)    *! @belongs Debug    *!    *! Debug function for showing the symbol table of a program.    *!    *! @returns    *! Returns an array of arrays with the following information    *! for each symbol in @[p]:    *! @array    *! @elem int modifiers
pike.git/src/builtin.cmod:981:    case 0: DO_IT (p_wchar0,SPACECASE8); break;    case 1: DO_IT (p_wchar1,SPACECASE16); break;    case 2: DO_IT (p_wchar2,SPACECASE16); break;   #undef DO_IT   #undef SPACECASE8   #undef SPACECASE16    }    RETURN string_slice (s, start, end + 1 - start);   }    + /*! @decl string status(int verbose) +  *! @belongs String +  *! +  *! Get string table statistics. +  *! +  *! @returns +  *! Returns a string with an ASCII table containing +  *! the current string table statistics. +  *! +  *! @note +  *! Currently returns the empty string (@expr{""@}) +  *! if @[verbose] is zero. +  *! +  *! @note +  *! The formatting and contents of the result +  *! may vary between different versions of Pike. +  */ + PIKEFUN string string_status(int verbose) +  errname String.status; + { +  RETURN add_string_status(verbose); + } +    /*! @decl int implements(program prog, program api)    *! @belongs Program    *!    *! Returns 1 if @[prog] implements @[api].    */   PMOD_EXPORT   PIKEFUN int program_implements(program prog, program api)    errname Program.implements;    optflags OPT_TRY_OPTIMIZE;   {
pike.git/src/builtin.cmod:1050:    }    else    push_int(0);   }      /*! @decl int(8..8)|int(16..16)|int(32..32) width(string s)    *! @belongs String    *!    *! Returns the width of a string.    *! -  *! Three return values are possible: -  *! @int -  *! @value 8 -  *! The string @[s] only contains characters <= 255. -  *! @value 16 -  *! The string @[s] only contains characters <= 65535. -  *! @value 32 -  *! The string @[s] contains characters >= 65536. -  *! @endint +  *! @returns +  *! Three return values are currently possible: +  *! @int +  *! @value 8 +  *! The string @[s] only contains characters <= 255. +  *! @value 16 +  *! The string @[s] only contains characters <= 65535. +  *! @value 32 +  *! The string @[s] contains characters >= 65536. +  *! @endint +  *! +  *! @note +  *! It is possible that a future version of Pike may return +  *! further values. In particular the width @expr{7@} seems +  *! like it could be useful.    */   PMOD_EXPORT   PIKEFUN int(8 .. 8)|int(16 .. 16)|int(32 .. 32) string_width(string s)    errname String.width;    optflags OPT_TRY_OPTIMIZE;   {    RETURN 8 * (1 << s->size_shift);   }      /*! @decl mixed m_delete(object|mapping map, mixed index)
pike.git/src/builtin.cmod:1403:    *! This function returns a random number in the range 0 - @[max]-1.    *!    *! @seealso    *! @[random_seed()]    */      PMOD_EXPORT   PIKEFUN int random(int i)   {    if(i <= 0) RETURN 0; - #if defined (AUTO_BIGNUM) && SIZEOF_INT_TYPE > 4 + #if SIZEOF_INT_TYPE > 4    if(i >> 31) {    unsigned INT_TYPE a = my_rand();    unsigned INT_TYPE b = my_rand();    RETURN (INT_TYPE)(((a<<32)|b) % i);    }   #endif    RETURN my_rand() % i;   }      PMOD_EXPORT
pike.git/src/builtin.cmod:2132:    push_constant_text("bytecode_method");    push_constant_text(PIKE_BYTECODE_METHOD_NAME);    push_constant_text("abi");    push_int(sizeof(void *) * 8);    push_constant_text("native_byteorder");    push_int(PIKE_BYTEORDER);    push_constant_text("int_size");    push_int(sizeof(INT_TYPE) * 8);    push_constant_text("float_size");    push_int(sizeof(FLOAT_TYPE) * 8); - #ifdef AUTO_BIGNUM +     push_constant_text("auto_bignum");    push_int(1);    f_aggregate_mapping(6*2); - #else -  f_aggregate_mapping(5*2); - #endif +    }      /*! @endmodule    */      void low_backtrace(struct Pike_interpreter_struct *i)   {    struct svalue *stack_top = i->stack_pointer;    struct pike_frame *f, *of = 0;    int size = 0;
pike.git/src/builtin.cmod:2319:    */   PIKECLASS Buffer   {    CVAR struct string_builder str;    CVAR int initial;       void f_Buffer_get_copy( INT32 args );    void f_Buffer_get( INT32 args );    void f_Buffer_add( INT32 args );    -  +     /*! @decl void create(int initial_size)    *!    *! Initializes a new buffer.    *!    *! If no @[initial_size] is specified, 256 is used. If you    *! know approximately how big the buffer will be, you can optimize    *! the operation of @[add()] (slightly) by passing the size to this    *! function.    */    PIKEFUN void create( int|void size )    {    struct Buffer_struct *str = THIS; -  if( args ) +  if( size )    str->initial = MAXIMUM( size->u.integer, 512 );    else    str->initial = 256;    }       /*! @decl string _sprintf( int flag, mapping flags )    *! It is possible to @[sprintf] a String.Buffer object    *! as @tt{%s@} just as if it was a string.    */    PIKEFUN string _sprintf( int flag, mapping flags )
pike.git/src/builtin.cmod:2588:    /*! @decl void putchar(int c)    *! Appends the character @[c] at the end of the string.    */    PIKEFUN void putchar(int c) {    struct Buffer_struct *str = THIS;    if(!str->str.s)    init_string_builder_alloc(&str->str, str->initial, 0);    string_builder_putchar(&str->str, c);    }    +  /*! @decl int sprintf(strict_sprintf_format format, sprintf_args ... args) +  *! Appends the output from @[sprintf] at the end of the string. +  *! Returns the resulting size of the String.Buffer. +  */ +  PIKEFUN int sprintf(mixed ... arguments) +  rawtype tFuncV(tAttr("strict_sprintf_format", tOr(tStr, tObj)), +  tAttr("sprintf_args", tMix), tStr); +  +  { +  // FIXME: Reset length on exception? +  struct Buffer_struct *str = THIS; +  if(!str->str.s) +  init_string_builder_alloc(&str->str, str->initial, 0); +  low_f_sprintf(args, 0, &str->str); +  RETURN str->str.s->len; +  } +     /*! @decl string get_copy()    *!    *! Get the data from the buffer. Significantly slower than @[get],    *! but does not clear the buffer.    */    PIKEFUN string get_copy()    {    struct pike_string *str = THIS->str.s;    if( str )    {
pike.git/src/builtin.cmod:3352:       PIKEFUN int `usec_full()    {    struct timeval now;       if( THIS->hard_update )    ACCURATE_GETTIMEOFDAY( &now );    else    INACCURATE_GETTIMEOFDAY( &now );    - #ifdef AUTO_BIGNUM +     push_int( now.tv_sec );    push_int( 1000000 );    f_multiply( 2 );    push_int( now.tv_usec );    f_add( 2 );    return; - #else -  RETURN (now.tv_sec * 1000000 + now.tv_usec); - #endif +     }       /*! @decl protected void create( int fast );    *!    *! If @[fast] is true, do not request a new time from the system,    *! instead use the global current time variable.    *!    *! This will only work in callbacks, but can save significant amounts    *! of CPU.    */
pike.git/src/builtin.cmod:3568:    push_svalue(tmpargs+e);    }    }    check_stack(depth * (args+1));    low_automap(1,depth,fun,tmpargs,args-1);    stack_unlink(args);   }      /* Linked list stuff.    */ - #undef INIT_BLOCK - #define INIT_BLOCK(NODE) do { \ -  (NODE)->next = (NODE)->prev = NULL; \ -  (NODE)->refs = 1; \ -  SET_SVAL((NODE)->val, T_INT, NUMBER_UNDEFINED, \ -  integer, 0); \ -  } while(0) + static struct block_allocator pike_list_node_allocator = BA_INIT_PAGES(sizeof(struct pike_list_node), 4);    - #undef EXIT_BLOCK - #define EXIT_BLOCK(NODE) do { \ -  if ((NODE)->prev) { \ -  free_list_node((NODE)->prev); \ -  } \ -  if ((NODE)->next) { \ -  free_list_node((NODE)->next); \ -  } \ -  free_svalue(&(NODE)->val); \ -  } while(0) + ATTRIBUTE((malloc)) + static struct pike_list_node * alloc_pike_list_node() { +  struct pike_list_node * node = ba_alloc(&pike_list_node_allocator); +  node->next = node->prev = NULL; +  node->refs = 1; +  SET_SVAL(node->val, T_INT, NUMBER_UNDEFINED, integer, 0); +  return node; + }    - BLOCK_ALLOC_FILL_PAGES(pike_list_node, 4); + void count_memory_in_pike_list_nodes(size_t * n, size_t * s) { +  ba_count_all(&pike_list_node_allocator, n, s); + }    -  + void free_all_pike_list_node_blocks() { +  ba_destroy(&pike_list_node_allocator); + } +    PMOD_EXPORT void free_list_node(struct pike_list_node *node)   {    if (!sub_ref(node)) { -  really_free_pike_list_node(node); +  if (node->prev) { +  free_list_node(node->prev);    } -  +  if (node->next) { +  free_list_node(node->next);    } -  +  free_svalue(&node->val); +  ba_free(&pike_list_node_allocator, node); +  } + }      PMOD_EXPORT void unlink_list_node(struct pike_list_node *n)   {   #ifdef PIKE_DEBUG    if (!n) {    Pike_fatal("Unlinking NULL node.\n");    }    if (!n->next || !n->prev) {    Pike_fatal("Unlinking unlinked node.\n");    }
pike.git/src/builtin.cmod:3889:    */    PIKEFUN string encode_json(...)    {    push_constant_text ("null");    }   }      /*! @endclass    */    + PMOD_EXPORT + PIKEFUN int levenshtein_distance(string a, string b) + { +  int i, j, n, *lev_i, *lev_p; +  +  /* Simple cases: strings are equal or one of them is empty: */ +  if (a == b) RETURN 0; +  if (a->len == 0) RETURN b->len; +  if (b->len == 0) RETURN a->len; +  +  /* Return -1 if any of the strings is wider than 8 bits: */ +  if (a->size_shift || b->size_shift) RETURN -1; +  +  /* Allocate two rows on the stack: */ +  n = b->len+1; +  lev_i = alloca(n*sizeof(int)); +  lev_p = alloca(n*sizeof(int)); +  if (!lev_i || !lev_p) RETURN -1; +  +  /* Initialise the first row */ +  for (j = 0; j < n; j++) lev_i[j] = j; +  +  for (i = 0; i < a->len; i++) +  { +  /* lev_p = row for i, lev_i = row for i+1: */ +  memcpy(lev_p, lev_i, n*sizeof(int)); +  lev_i[0] = i + 1; +  for (j = 0; j < b->len; j++) +  { +  int cost = (a->str[i] == b->str[j]) ? 0 : 1; +  int test, min_val = lev_i[j]+1; +  if ((test = lev_p[j+1]+1) < min_val) min_val = test; +  if ((test = lev_p[j]+cost) < min_val) min_val = test; +  lev_i[j+1] = min_val; +  } +  } +  RETURN lev_i[b->len]; + } +    /*! @endmodule    */      /*! @module Serializer    */      /*! @class Serializable    *!    *! The base class for serializable objects.    *!
pike.git/src/builtin.cmod:5147:      PIKECLASS __Backtrace_Tester__   {    INIT {    Pike_error("__Backtrace_Tester__\n");    }   }      void init_builtin(void)   { -  init_pike_list_node_blocks(); +     INIT   }      void exit_builtin(void)   {    if (val_module) free_object (val_module);    EXIT   #ifndef DO_PIKE_CLEANUP    /* This is performed by exit_builtin_modules() at a later point    * in this case, so that the pike_list_node's are valid at cleanup    * time, thus avoiding "got invalid pointer" fatals at exit.    */ -  free_all_pike_list_node_blocks(); +  ba_destroy(&pike_list_node_allocator);   #endif   #ifndef USE_SETENV    if (env_allocs) free_mapping (env_allocs);   #endif   }