pike.git / lib / master.pike.in

version» Context lines:

pike.git/lib/master.pike.in:2:   //   // Master Control Program for Pike.   //   // 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.   //      #pike __REAL_VERSION__   //#pragma strict_types + #pragma dynamic_dot      //! @appears predef::MasterObject   //!   //! Master control program for Pike.   //!   //! @seealso   //! @[predef::master()], @[predef::replace_master()]      // --- Some configurable parameters   
pike.git/lib/master.pike.in:48:   // Enables the out of date warning in low_findprog().   #ifndef OUT_OF_DATE_WARNING   #define OUT_OF_DATE_WARNING 1   #endif /* OUT_OF_DATE_WARNING */   constant out_of_date_warning = OUT_OF_DATE_WARNING;      // FIXME: PATH_SEPARATOR and UPDIR should probably be exported,   // or at least some functions that use them should be.   // cf Tools.Shoot.runpike.   // /grubba 2004-04-11 - #if defined(__NT__) || defined(__amigaos__) || defined(__OS2__) + #if defined(__NT__)   #define PATH_SEPARATOR ";"   #else   #define PATH_SEPARATOR ":"   #endif    - #ifdef __amigaos__ - #define UPDIR "/" - #else +    #define UPDIR "../" - #endif +       //! @decl constant out_of_date_warning = 1   //! Should Pike complain about out of date compiled files.   //! 1 means yes and 0 means no. Controlled by the OUT_OF_DATE_WARNING   //! define.      //! If not zero compilation warnings will be written out on stderr.   int want_warnings = PIKE_WARNINGS;    -  + //! Major pike version to emulate.   //! -  + //! This is typically set via the option @expr{"-V"@}. + //! + //! @seealso + //! @[compat_minor]   int compat_major=-1;    -  + //! Minor pike version to emulate.   //! -  + //! This is typically set via the option @expr{"-V"@}. + //! + //! @seealso + //! @[compat_major]   int compat_minor=-1;    -  + //! Show compilation warnings from compilation of @[cpp()] + //! @expr{#if constant()@} expressions.   //! -  + //! This is typically set via the option @expr{"--picky-cpp"@}.   int show_if_constant_errors = 0;      int is_pike_master = 0;   // This integer variable should exist in any object that aspires to be   // the master. It gets set to 1 when the master is installed, and is   // therefore set in any object that is or has been the master. That   // makes the Encoder class encode references to the master and all   // ex-masters as references to the current master object.    -  + mapping(string:object) fs_map = ([]); + object root_fs;   // --- Functions begin here.      // Have to access some stuff without going through the resolver.   private object(_static_modules.Builtin) Builtin = _static_modules.Builtin();   private constant Files = _static_modules._Stdio;      #define Stat Files.Stat   #define capitalize(X) (upper_case((X)[..0])+(X)[1..]) - #define trim_all_whites(X) (Builtin.string_trim_all_whites (X)) + #define trim(X) (Builtin.string_trim (X))      private function write = Files()->_stdout->write;   private function werror = Files()->_stderr->write;      // Tell Pike.count_memory this is global.   constant pike_cycle_depth = 0;      //#define RECUR_COMPILE_DEBUG   // More brief than RESOLV_DEBUG. Usually enough to find those pesky   // "Recursive module dependency" bugs. :P
pike.git/lib/master.pike.in:150:   #define INC_RESOLV_MSG_DEPTH() 0   #define DEC_RESOLV_MSG_DEPTH() 0   #define resolv_debug(X...) do {} while (0)   #endif // !RESOLV_DEBUG      constant no_value = (<>);   constant NoValue = typeof (no_value);      // Some API compatibility stuff.    - //! Pike 0.5 master compatibility interface. + //! Pike 7.8 master compatibility interface.   //!   //! Most of the interface is implemented via mixin,   //! or overloading by more recent masters.   //!   //! This interface is used for compatibility with - //! all pikes until Pike 0.5. + //! Pike 7.8.   //!   //! @deprecated predef::MasterObject   //!   //! @seealso   //! @[get_compat_master()], @[master()], @[predef::MasterObject] - protected class Pike_0_5_master + protected class Pike_7_8_master   { -  string describe_backtrace(array(mixed) trace); -  object low_cast_to_object(string oname, string current_file); +     extern array(string) pike_include_path; -  string pike_library_path = - #if "#lib_prefix#"[0]!='#' -  "#lib_prefix#" - #else -  dirname(__FILE__) - #endif -  ; +     extern array(string) pike_module_path;    extern array(string) pike_program_path;   #ifdef GETCWD_CACHE    extern string current_path;    int cd(string s);    string getcwd();   #endif    string combine_path_with_cwd(string path);   #ifdef FILE_STAT_CACHE    extern int invalidate_time;    extern mapping(string:multiset(string)) dir_cache;   #endif -  local array(mixed) master_file_stat(string x) -  { -  Stat st = global::master_file_stat(x); -  return st && (array)st; -  } +     -  //! @decl mapping(string:array(string)) environment -  //! -  //! Mapping containing the environment variables. -  //! -  //! The mapping currently has the following structure: -  //! @mapping -  //! @member array(string) index -  //! Note that the index is @[lower_case()]'d on NT. -  //! @array -  //! @elem string varname -  //! Variable name with case intact. -  //! @elem string value -  //! Variable value. -  //! @endarray -  //! @endmapping -  //! -  //! @note -  //! This mapping should not be accessed directly; use @[getenv()] -  //! and @[putenv()] instead. This mapping is not publicly -  //! accessible in pikes newer than 7.6. -  //! -  //! @note -  //! This mapping is not compatible with @[Process.create_process()]; -  //! use the mapping returned from calling @[getenv()] without arguments -  //! instead. -  //! -  //! @bugs -  //! This mapping is not the real environment; it is just a copy of -  //! the environment made at startup. Pike does attempt to keep -  //! track of changes in the mapping and to reflect them in the -  //! real environment, but avoid accessing this mapping if at all -  //! possible. -  +     string|mapping(string:string) getenv(string|void s);    void putenv(string|void varname, string|void value);    -  // compat_environment is the mapping returned by `environment -  // (if any). -  // compat_environment_copy is used to keep track of any changes -  // performed destructively on the compat_environment mapping. -  // Both should be zero if not in use. -  protected mapping(string:array(string)) compat_environment; -  protected mapping(string:array(string)) compat_environment_copy; -  - #pragma no_deprecation_warnings -  local __deprecated__(mapping(string:array(string))) `environment() -  { -  if (compat_environment) return compat_environment; -  compat_environment_copy = ([]); - #ifdef __NT__ -  // Can't use the cached environment returned by getenv(), since -  // variable names have been lowercased there. -  foreach((array(array(string)))Builtin._getenv(), array(string) pair) { -  compat_environment_copy[lower_case(pair[0])] = pair; -  } - #else -  foreach((array(array(string)))getenv(), array(string) pair) { -  compat_environment_copy[pair[0]] = pair; -  } - #endif -  return compat_environment = copy_value(compat_environment_copy); -  } -  -  local void `environment=(__deprecated__(mapping(string:array(string))) -  new_env) -  { -  compat_environment = new_env; -  if (!new_env) -  compat_environment_copy = 0; -  else if (!compat_environment_copy) -  compat_environment_copy = ([]); -  } - #pragma deprecation_warnings -  +     void add_include_path(string tmp);    void remove_include_path(string tmp);    void add_module_path(string tmp);    void remove_module_path(string tmp);    void add_program_path(string tmp);    void remove_program_path(string tmp);    mapping(string:program|NoValue) programs; -  program cast_to_program(string pname, string current_file); -  void handle_error(array(mixed) trace); +     -  //! Make a new instance of a class. -  //! -  //! @note -  //! This function should not be used. It is here for -  //! compatibility reasons only. -  local __deprecated__ object new(mixed prog, mixed ... args) -  { -  if(stringp(prog)) -  prog=cast_to_program(prog,backtrace()[-2][0]); -  return prog(@args); -  } -  -  void create(); -  program handle_inherit(string pname, string current_file); +     extern mapping(program:object) objects; -  object low_cast_to_object(string oname, string current_file); +     object cast_to_object(string oname, string current_file);    class dirnode {}; -  object findmodule(string fullname); -  local protected object Pike_0_5_compat_handler; -  local mixed resolv(string identifier, string|void current_file) -  { -  if (!Pike_0_5_compat_handler) { -  Pike_0_5_compat_handler = global::get_compilation_handler(0, 5); -  } -  return Pike_0_5_compat_handler->resolv(identifier, current_file); -  } +     extern string _master_file_name;    void _main(array(string) orig_argv, array(string) env);    extern mixed inhibit_compile_errors;    void set_inhibit_compile_errors(mixed f);    string trim_file_name(string s);    void compile_error(string file,int line,string err);    string handle_include(string f, string current_file, int local_include); -  local __deprecated__ string stupid_describe(mixed m) -  { -  switch(string typ=sprintf("%t",m)) -  { -  case "int": -  case "float": -  return (string)m; +     -  case "string": -  if(sizeof(m) < BT_MAX_STRING_LEN) -  { -  string t = sprintf("%O", m); -  if (sizeof(t) < (BT_MAX_STRING_LEN + 2)) { -  return t; -  } -  t = 0; -  } -  -  case "array": -  case "mapping": -  case "multiset": -  return typ+"["+sizeof(m)+"]"; -  -  default: -  return typ; -  } -  } -  -  string describe_backtrace(array(mixed) trace); -  -  object get_compat_master(int major, int minor) -  { -  // 0.0 - 0.5 -  if (!major && (minor < 6)) -  return this_program::this; -  return get_compat_master(major, minor); -  } -  -  /* Missing symbols: -  * -  * __INIT -  * __lambda_30 (Alias for mkmapping().) -  */ - } -  - //! Pike 0.6 master compatibility interface. - //! - //! Most of the interface is implemented via mixin, - //! or overloading by more recent masters. - //! - //! This interface is used for compatibility with - //! Pike 0.6. - //! - //! @deprecated predef::MasterObject - //! - //! @seealso - //! @[get_compat_master()], @[master()], @[predef::MasterObject] - protected class Pike_0_6_master - { -  inherit Pike_0_5_master; +     int is_absolute_path(string p);    array(string) explode_path(string p);    string dirname(string x);    string basename(string x);    object low_cast_to_object(string oname, string current_file); - #pragma no_deprecation_warnings -  private __deprecated__(string) pike_library_path = -  (__deprecated__(string))Pike_0_5_master::pike_library_path; - #pragma deprecation_warnings +     extern int want_warnings;    program compile_string(string data, void|string name);    program compile_file(string file);    - #if constant(_static_modules.Builtin.mutex) -  extern object compilation_mutex; - #endif -  -  local constant mkmultiset = predef::mkmultiset; -  local __deprecated__(function) clone = new; +     constant master_efuns = ({});    class joinnode {};    extern mapping(string:mixed) fc; -  mixed handle_import(string what, string|void current_file); -  local protected object Pike_0_6_compat_handler; -  local mixed resolv(string identifier, string|void current_file) -  { -  if (!Pike_0_6_compat_handler) { -  Pike_0_6_compat_handler = global::get_compilation_handler(0, 6); -  } -  return Pike_0_6_compat_handler->resolv(identifier, current_file); -  } +     extern string _pike_file_name;    void compile_warning(string file,int line,string err);    string read_include(string f);    -  string describe_program(program p); -  string describe_backtrace(array(mixed) trace); +     class Codec {};    -  object get_compat_master(int major, int minor) -  { -  if (!major && (minor < 6)) -  return Pike_0_5_master::get_compat_master(major, minor); -  // 0.6 -  if (!major && (minor < 7)) -  return this_program::this; -  return get_compat_master(major, minor); -  } -  -  /* Missing symbols: -  * -  * __INIT -  */ - } -  - //! Pike 7.0 master compatibility interface. - //! - //! Most of the interface is implemented via mixin, - //! or overloading by more recent masters. - //! - //! This interface is used for compatibility with - //! Pike 0.7 through 7.0. - //! - //! @deprecated predef::MasterObject - //! - //! @seealso - //! @[get_compat_master()], @[master()], @[predef::MasterObject] - class Pike_7_0_master - { -  inherit Pike_0_6_master; +     constant bt_max_string_len = 1;    constant out_of_date_warning = 1;   #ifdef PIKE_FAKEROOT    extern object o;    string fakeroot(string s);   #endif   #ifdef PIKE_AUTORELOAD    extern int autoreload_on;    extern int newest;    extern mapping(string:int) load_time;   #endif    string master_read_file();    string normalize_path(string X);    array(string) query_precompiled_names(string fname);    program cast_to_program(string pname, string current_file,    object|void handler);    void handle_error(array(mixed)|object trace); -  protected private constant mkmultiset = mkmultiset; +     program handle_inherit(string pname, string current_file, object|void handler);    mixed handle_import(string what, string|void current_file, object|void handler);    mixed resolv_base(string identifier, string|void current_file);    -  // FIXME: Not in 7.7! -  extern mapping resolv_cache; -  local protected object Pike_7_0_compat_handler; -  local mixed resolv(string identifier, string|void current_file) -  { -  if (!Pike_7_0_compat_handler) { -  Pike_7_0_compat_handler = global::get_compilation_handler(7, 0); -  } -  return Pike_7_0_compat_handler->resolv(identifier, current_file); -  } +     mixed get_inhibit_compile_errors();    string decode_charset(string data, string charset); -  local __deprecated__(int) clipped=0; -  local __deprecated__(int) canclip=0; - #pragma no_deprecation_warnings -  local __deprecated__ string stupid_describe(mixed m, int maxlen) -  { -  string typ; -  if (catch (typ=sprintf("%t",m))) -  typ = "object"; // Object with a broken _sprintf(), probably. -  switch(typ) -  { -  case "int": -  case "float": -  return (string)m; +     -  case "string": -  canclip++; -  if(sizeof(m) < maxlen) -  { -  string t = sprintf("%O", m); -  if (sizeof(t) < (maxlen + 2)) { -  return t; -  } -  t = 0; -  } -  clipped++; -  if(maxlen>10) -  { -  return sprintf("%O+[%d]",m[..maxlen-5],sizeof(m)-(maxlen-5)); -  }else{ -  return "string["+sizeof(m)+"]"; -  } -  -  case "array": -  if(!sizeof(m)) return "({})"; -  if(maxlen<5) -  { -  clipped++; -  return "array["+sizeof(m)+"]"; -  } -  canclip++; -  return "({" + stupid_describe_comma_list(m,maxlen-2) +"})"; -  -  case "mapping": -  if(!sizeof(m)) return "([])"; -  return "mapping["+sizeof(m)+"]"; -  -  case "multiset": -  if(!sizeof(m)) return "(<>)"; -  return "multiset["+sizeof(m)+"]"; -  -  case "function": -  if(string tmp=describe_program(m)) return tmp; -  if(object o=function_object(m)) -  return (describe_object(o)||"")+"->"+function_name(m); -  else { -  string tmp; -  if (catch (tmp = function_name(m))) -  // The function object has probably been destructed. -  return "function"; -  return tmp || "function"; -  } -  -  case "program": -  if(string tmp=describe_program(m)) return tmp; -  return typ; -  -  default: -  if (objectp(m)) -  if(string tmp=describe_object(m)) return tmp; -  return typ; -  } -  } -  local __deprecated__ string stupid_describe_comma_list(array x, int maxlen) -  { -  string ret=""; -  -  if(!sizeof(x)) return ""; -  if(maxlen<0) return ",,,"+sizeof(x); -  -  int clip=min(maxlen/2,sizeof(x)); -  int len=maxlen; -  int done=0; -  - // int loopcount=0; -  -  while(1) -  { - // if(loopcount>10000) werror("len=%d\n",len); -  array(string) z=allocate(clip); -  array(int) isclipped=allocate(clip); -  array(int) clippable=allocate(clip); -  for(int e=0;e<clip;e++) -  { -  clipped=0; -  canclip=0; -  z[e]=stupid_describe(x[e],len); -  isclipped[e]=clipped; -  clippable[e]=canclip; -  } -  -  while(1) -  { - // if(loopcount>10000) werror("clip=%d maxlen=%d\n",clip,maxlen); -  string ret = z[..clip-1]*","; - // if(loopcount>10000) werror("sizeof(ret)=%d z=%O isclipped=%O done=%d\n",sizeof(ret),z[..clip-1],isclipped[..clip-1],done); -  if(done || sizeof(ret)<=maxlen+1) -  { -  int tmp=sizeof(x)-clip-1; - // if(loopcount>10000) werror("CLIPPED::::: %O\n",isclipped); -  clipped=`+(0,@isclipped); -  if(tmp>=0) -  { -  clipped++; -  ret+=",,,"+tmp; -  } -  canclip++; -  return ret; -  } -  -  int last_newlen=len; -  int newlen; -  int clipsuggest; -  while(1) -  { - // if(loopcount++ > 20000) return ""; - // if(!(loopcount & 0xfff)) werror("GNORK\n"); -  int smallsize=0; -  int num_large=0; -  clipsuggest=0; -  -  for(int e=0;e<clip;e++) -  { - // if(loopcount>10000) werror("sizeof(z[%d])=%d len=%d\n",e,sizeof(z[e]),len); -  -  if((sizeof(z[e])>=last_newlen || isclipped[e]) && clippable[e]) -  num_large++; -  else -  smallsize+=sizeof(z[e]); -  -  if(num_large * 15 + smallsize < maxlen) clipsuggest=e+1; -  } -  - // if(loopcount>10000) werror("num_large=%d maxlen=%d smallsize=%d clippsuggest=%d\n",num_large,maxlen,smallsize,clipsuggest); -  newlen=num_large ? (maxlen-smallsize)/num_large : 0; -  - // if(loopcount>10000) werror("newlen=%d\n",newlen); -  -  if(newlen<8 || newlen >= last_newlen) break; -  last_newlen=newlen; - // if(loopcount>10000) werror("len decreased, retrying.\n"); -  } -  -  if(newlen < 8 && clip) -  { -  clip-= (clip/4) || 1; -  if(clip > clipsuggest) clip=clipsuggest; - // if(loopcount>10000) werror("clip decreased, retrying.\n"); -  }else{ -  len=newlen; -  done++; -  break; -  } -  } -  } -  -  return ret; -  } - #pragma deprecation_warnings -  +     string describe_object(object o);    string describe_backtrace(array(mixed) trace, void|int linewidth);    string describe_error(mixed trace);    -  object get_compat_master(int major, int minor) -  { -  if (!major && (minor < 7)) -  return Pike_0_6_master::get_compat_master(major, minor); -  // 0.7 - 7.0 -  if ((major < 7) || ((major == 7) && !minor)) -  return this_program::this; -  return get_compat_master(major, minor); -  } +  // ---    -  /* No missing symbols. */ - } -  - //! Pike 7.2 master compatibility interface. - //! - //! Most of the interface is implemented via mixin, - //! or overloading by more recent masters. - //! - //! This interface is used for compatibility with - //! Pike 7.1 and 7.2. - //! - //! @deprecated predef::MasterObject - //! - //! @seealso - //! @[get_compat_master()], @[master()], @[predef::MasterObject] - protected class Pike_7_2_master - { -  inherit Pike_7_0_master; +    #ifdef PIKE_MODULE_RELOC    string relocate_module(string s);    string unrelocate_module(string s);   #endif    extern int compat_major;    extern int compat_minor;    Stat master_file_stat(string x);    object low_cast_to_object(string oname, string current_file,    object|void current_handler);    object findmodule(string fullname, object|void handler);    extern multiset no_resolv;    extern string ver;    mapping get_default_module(); -  local protected object Pike_7_2_compat_handler; -  local mixed resolv(string identifier, string|void current_file) -  { -  if (!Pike_7_2_compat_handler) { -  Pike_7_2_compat_handler = global::get_compilation_handler(7, 2); -  } -  return Pike_7_2_compat_handler->resolv(identifier, current_file); -  } +     void runtime_warning(string where, string what, mixed ... args);    protected int clipped;    protected int canclip;    protected string stupid_describe(mixed m, int maxlen);    protected string stupid_describe_comma_list(array x, int maxlen);    class Describer {};    string describe_function(function f);    class CompatResolver {};    int(0..1) asyncp();    class Version {};    extern object currentversion;    extern mapping(object:object) compat_handler_cache;    object get_compilation_handler(int major, int minor); -  string _sprintf(int|void t); -  object get_compat_master(int major, int minor) -  { -  if ((major < 7) || ((major == 7) && (minor < 1))) -  return Pike_7_0_master::get_compat_master(major, minor); -  // 7.1 & 7.2 -  if ((major == 7) && (minor < 3)) -  return this_program::this; -  return get_compat_master(major, minor); -  } +     -  /* No missing symbols. */ - } +  // ---    - //! Pike 7.4 master compatibility interface. - //! - //! Most of the interface is implemented via mixin, - //! or overloading by more recent masters. - //! - //! This interface is used for compatibility with - //! Pike 7.3 and 7.4. - //! - //! @deprecated predef::MasterObject - //! - //! @seealso - //! @[get_compat_master()], @[master()], @[predef::MasterObject] - protected class Pike_7_4_master - { -  inherit Pike_7_2_master; +    #ifdef RESOLV_DEBUG    void resolv_debug (sprintf_format fmt, sprintf_args... args);   #endif    void error(sprintf_format f, sprintf_args ... args); - #ifdef GETCWD_CACHE -  protected extern string current_path; - #endif +     constant no_value = (<>);    constant NoValue = typeof (no_value);    string programs_reverse_lookup (program prog);    program objects_reverse_lookup (object obj);    string fc_reverse_lookup (object obj); -  // Hide clone() and new(). -  private local __deprecated__ object new(mixed prog, mixed ... args){} -  private local __deprecated__(function) clone = new; +     void unregister(program p);    program low_cast_to_program(string pname,    string current_file,    object|void handler,    void|int mkobj);    extern string include_prefix;    extern mapping(string:string) predefines; -  // FIXME: Not in 7.7! -  extern CompatResolver parent_resolver; +     void add_predefine (string name, string value);    void remove_predefine (string name);    mapping get_predefines();   #if constant(thread_create)    object backend_thread();   #endif    function(string:string) set_trim_file_name_callback(function(string:string) s);    int compile_exception (array|object trace);    string program_path_to_name ( string path,    void|string module_prefix,
pike.git/lib/master.pike.in:796:    // Codec::Decoder:    extern string fname;    extern int mkobj;    object __register_new_program(program p);    object objectof (string|array what);    function functionof (string|array what);    program programof (string|array what);    void decode_object(object o, mixed data);       string _sprintf(int t); -  local protected object Pike_7_4_compat_handler; -  local mixed resolv(string identifier, string|void current_file) -  { -  if (!Pike_7_4_compat_handler) { -  Pike_7_4_compat_handler = global::get_compilation_handler(7, 4); -  } -  return Pike_7_4_compat_handler->resolv(identifier, current_file); -  } -  object get_compat_master(int major, int minor) -  { -  if ((major < 7) || ((major == 7) && (minor < 3))) -  return Pike_7_2_master::get_compat_master(major, minor); -  // 7.3 & 7.4 -  if ((major == 7) && (minor < 5)) -  return this_program::this; -  return get_compat_master(major, minor); -  } +     -  /* No missing symbols. */ - } +  // ---    - //! Pike 7.6 master compatibility interface. - //! - //! Most of the interface is implemented via mixin, - //! or overloading by more recent masters. - //! - //! This interface is used for compatibility with - //! Pike 7.5 and 7.6. - //! - //! @deprecated predef::MasterObject - //! - //! @seealso - //! @[get_compat_master()], @[master()], @[predef::MasterObject] - protected class Pike_7_6_master - { -  inherit Pike_7_4_master; -  +     extern int show_if_constant_errors; -  protected void create(); +     extern mapping(string:string) initial_predefines;    extern joinnode root_module;    extern mapping(object:joinnode) handler_root_modules;    extern array(string) system_module_path; -  protected extern CompatResolver parent_resolver; -  protected extern mapping resolv_cache; +     extern CompatResolver fallback_resolver;    joinnode get_root_module(object|void current_handler); -  class Pike06Resolver {} -  local protected object Pike_7_6_compat_handler; +  local protected object Pike_7_8_compat_handler;    local mixed resolv_or_error(string identifier, string|void current_file,    void|object current_handler)    { -  if (!Pike_7_6_compat_handler) { -  Pike_7_6_compat_handler = global::get_compilation_handler(7, 6); +  if (!Pike_7_8_compat_handler) { +  Pike_7_8_compat_handler = global::get_compilation_handler(7, 8);    } -  return Pike_7_6_compat_handler->resolv_or_error(identifier, current_file, +  return Pike_7_8_compat_handler->resolv_or_error(identifier, current_file,    current_handler);    }    local mixed resolv(string identifier, string|void current_file)    { -  if (!Pike_7_6_compat_handler) { -  Pike_7_6_compat_handler = global::get_compilation_handler(7, 6); +  if (!Pike_7_8_compat_handler) { +  Pike_7_8_compat_handler = global::get_compilation_handler(7, 8);    } -  return Pike_7_6_compat_handler->resolv(identifier, current_file); +  return Pike_7_8_compat_handler->resolv(identifier, current_file);    }    array get_backtrace (object|array err);    object get_compat_master(int major, int minor)    { -  if ((major < 7) || ((major == 7) && (minor < 5))) -  return Pike_7_4_master::get_compat_master(major, minor); -  // 7.5 & 7.6 -  if ((major == 7) && (minor < 7)) -  return this_program::this; +  // 0.0 .. 7.8 +  if (major < 8) +  return this::this;    return get_compat_master(major, minor);    }       /* No missing symbols. */   }    - //! Pike 7.8 master compatibility interface. + //! Pike 8.0 master compatibility interface.   //!   //! Most of the interface is implemented via mixin,   //! or overloading by more recent masters.   //!   //! This interface is used for compatibility with - //! Pike 7.7 and 7.8. + //! Pike 8.0.   //!   //! @deprecated predef::MasterObject   //!   //! @seealso   //! @[get_compat_master()], @[master()], @[predef::MasterObject] - protected class Pike_7_8_master + protected class Pike_8_0_master   { -  inherit Pike_7_6_master; +  inherit Pike_7_8_master;    -  local protected object Pike_7_8_compat_handler; +  local protected object Pike_8_0_compat_handler;    local mixed resolv_or_error(string identifier, string|void current_file,    void|object current_handler)    { -  if (!Pike_7_8_compat_handler) { -  Pike_7_8_compat_handler = global::get_compilation_handler(7, 8); +  if (!Pike_8_0_compat_handler) { +  Pike_8_0_compat_handler = global::get_compilation_handler(8, 0);    } -  return Pike_7_8_compat_handler->resolv_or_error(identifier, current_file, +  return Pike_8_0_compat_handler->resolv_or_error(identifier, current_file,    current_handler);    }    local mixed resolv(string identifier, string|void current_file)    { -  if (!Pike_7_8_compat_handler) { -  Pike_7_8_compat_handler = global::get_compilation_handler(7, 8); +  if (!Pike_8_0_compat_handler) { +  Pike_8_0_compat_handler = global::get_compilation_handler(8, 0);    } -  return Pike_7_8_compat_handler->resolv(identifier, current_file); +  return Pike_8_0_compat_handler->resolv(identifier, current_file);    }    object get_compat_master(int major, int minor)    { -  if ((major < 7) || ((major == 7) && (minor < 7))) -  return Pike_7_6_master::get_compat_master(major, minor); -  // 7.5 & 7.6 -  if ((major == 7) && (minor < 9)) -  return this_program::this; +  if (major < 8) +  return Pike_7_8_master::get_compat_master(major, minor); +  // 8.0 +  if ((major == 8) && (minor < 1)) +  return this::this;    return get_compat_master(major, minor);    }   }      //! Namespaces for compat masters.   //!   //! This inherit is used to provide compatibility namespaces   //! for @[get_compat_master()].   //!   //! @seealso   //! @[get_compat_master()] - protected inherit Pike_7_8_master; + protected inherit Pike_8_0_master;    - //! @appears error + //! @namespace predef:: +    //! Throws an error. A more readable version of the code   //! @expr{throw( ({ sprintf(f, @@args), backtrace() }) )@}.   void error(sprintf_format f, sprintf_args ... args) {    if (sizeof(args)) f = sprintf(f, @args);    throw( ({ f, backtrace()[..<1] }) );   }      // FIXME: Should the pikeroot-things be private?   #ifdef PIKE_FAKEROOT   object o;
pike.git/lib/master.pike.in:998:    return s;   }      #ifdef fakeroot   #undef fakeroot   #endif   #define fakeroot relocate_module   #endif // PIKE_MODULE_RELOC       - //! @appears is_absolute_path +    //! Check if a path @[p] is fully qualified (ie not relative).   //!   //! @returns   //! Returns 1 if the path is absolute, 0 otherwise.   int is_absolute_path(string p)   { - #ifdef __amigaos__ - #define IS_ABSOLUTE_PATH(X) (search((X),":")>0) -  return IS_ABSOLUTE_PATH(p); - #else - #if defined(__NT__) || defined(__OS2__) + #if defined(__NT__)    p=replace(p,"\\","/");    if(sscanf(p,"%[a-zA-Z]:%*c",string s)==2 && sizeof(s)==1)    return 1;   #define IS_ABSOLUTE_PATH is_absolute_path   #else   #define IS_ABSOLUTE_PATH(X) has_prefix((X),"/")   #endif    return has_prefix(p,"/"); - #endif +    }    - #if defined(__NT__) || defined(__OS2__) + #if defined(__NT__)   #define EXPLODE_PATH(X) (replace((X),"\\","/")/"/")   #else   #define EXPLODE_PATH(X) ((X)/"/")   #endif    - //! @appears explode_path +    //! Split a path @[p] into its components.   //!   //! This function divides a path into its components. This might seem like   //! it could be done by dividing the string on <tt>"/"</tt>, but that will   //! not work on some operating systems. To turn the components back into   //! a path again, use @[combine_path()].   //!   array(string) explode_path(string p)   { - #ifdef __amigaos__ -  int colon = search(reverse(p), ":"); -  if(colon >= 0) -  return ({ p[..<colon] }) + explode_path(p[<colon+1..]); -  array(string) r = p/"/"; -  return replace(r[..<1], "", "/")+r[<0..]; - #else +     array(string) r = EXPLODE_PATH(p);    if(r[0] == "" && sizeof(p))    r[0] = "/";    return r; - #endif +    }    - //! @appears dirname +    //! Returns all but the last segment of a path. Some example inputs and   //! outputs:   //!   //! @xml{<matrix>   //! <r><c><b>Expression</b></c><c><b>Value</b></c></r>   //! <r><c>dirname("/a/b")</c><c>"/a"</c></r>   //! <r><c>dirname("/a/")</c><c>"/a"</c></r>   //! <r><c>dirname("/a")</c><c>"/"</c></r>   //! <r><c>dirname("/")</c><c>"/"</c></r>   //! <r><c>dirname("")</c><c>""</c></r>   //! </matrix>@}   //!   //! @seealso   //! @[basename()], @[explode_path()]   string dirname(string x)   {    if(x=="") return ""; - #ifdef __amigaos__ +     array(string) tmp=x/":";    array(string) tmp2=tmp[-1]/"/";    tmp[-1]=tmp2[..<1]*"/";    if(sizeof(tmp2) >= 2 && tmp2[-2]=="") tmp[-1]+="/";    return tmp*":"; - #else -  array(string) tmp=EXPLODE_PATH(x); -  if(x[0]=='/' && sizeof(tmp)<3) return "/"; -  return tmp[..<1]*"/"; - #endif +    }    - //! @appears basename +    //! Returns the last segment of a path.   //!   //! @seealso   //! @[dirname()], @[explode_path()]   string basename(string x)   { - #ifdef __amigaos__ -  return ((x/":")[-1]/"/")[-1]; - #define BASENAME(X) ((((X)/":")[-1]/"/")[-1]) - #else +     array(string) tmp=EXPLODE_PATH(x);    return tmp[-1];   #define BASENAME(X) (EXPLODE_PATH(X)[-1]) - #endif +    }      #ifdef PIKE_AUTORELOAD      int autoreload_on;   int newest;      #define AUTORELOAD_BEGIN() \    int ___newest=newest; \    newest=0
pike.git/lib/master.pike.in:1125:    if(autoreload_on) { \    int mtime = get_precompiled_mtime (X); \    if (mtime >= 0 && mtime > newest) \    if(s->mtime>newest) newest=[int]s->mtime; \    } \    } while(0)      #define AUTORELOAD_FINISH(VAR, CACHE, FILE) \    if(autoreload_on) { \    mixed val = CACHE[FILE]; \ -  if(!zero_type (val) && val != no_value && \ +  if(!undefinedp (val) && val != no_value && \    newest <= load_time[FILE]) { \    VAR = val; \    } \    } \    load_time[FILE] = newest; \    if(___newest > newest) newest=___newest;         mapping(string:int) load_time=([]);   #else      #define AUTORELOAD_CHECK_FILE(X)   #define AUTORELOAD_BEGIN()   #define AUTORELOAD_FINISH(VAR,CACHE,FILE)      #endif // PIKE_AUTORELOAD    - //! @appears compile_string + protected class CompilerEnvironment + { +  inherit predef::CompilerEnvironment : OrigCompilerEnvironment; +  +  mixed resolv(string identifier, string filename, +  object|void handler, object|void compat_handler) +  { +  return master()->resolv(identifier, filename, +  handler, compat_handler); +  } +  +  program handle_inherit(string inh, string current_file, +  object|void handler, object|void compat_handler) +  { +  return master()->handle_inherit(inh, current_file, +  handler, compat_handler); +  } +  +  program handle_import(string module, string current_file, +  object|void handler, object|void compat_handler) +  { +  return master()->handle_import(module, current_file, +  handler, compat_handler); +  } +  +  object get_compilation_handler(int major, int minor) +  { +  return master()->get_compilation_handler(major, minor); +  } +  +  int compile_exception(mixed err) +  { +  function(mixed:int) fun = master()->compile_exception; +  return fun && fun(err); +  } +  +  string format_exception(mixed err) +  { +  return 0; +  } +  +  class CPP +  { +  inherit ::this_program; +  + #if constant(_static_modules.Builtin.__HAVE_CPP_NO_HANDLERS__) +  object handler; +  object compat_handler; + #endif +  +  protected mixed apply_handler(string fun, mixed ... args) +  { +  function f; +  foreach(({ handler, compat_handler }), object o) { +  if (objectp(o) && functionp(f = predef::`->(o, fun))) { +  return f(@args); +  } +  } +  return CompilerEnvironment::`->(fun)(@args); +  } +  +  //! @decl void report(SeverityLevel severity, @ +  //! string filename, int(1..) linenumber, @ +  //! string subsystem, @ +  //! sprintf_format message, sprintf_args ... extra_args) +  //! +  //! Report a diagnostic from the preprocessor. +  //! +  //! @param severity +  //! The severity of the diagnostic. +  //! +  //! @param filename +  //! @param linenumber +  //! Location which triggered the diagnostic. +  //! +  //! @param subsystem +  //! Typically @expr{"cpp"@}. +  //! +  //! @param message +  //! String with the diagnostic message, with optional +  //! @[sprintf()]-style formatting (if any @[extra_args]). +  //! +  //! @param extra_args +  //! Extra arguments to @[sprintf()]. +  //! +  //! The default implementation does the following: +  //! +  //! @ul +  //! @item +  //! If there's a handler which implements @[Reporter()->report()], +  //! call it with the same arguments. +  //! @item +  //! Otherwise if there's a handler which implements +  //! @[compile_warning()] or @[compile_error()] that matches +  //! @[severity], call it with suitable arguments. +  //! @item +  //! Otherwise if there's a compat handler, use it in the same +  //! manner as the handler. +  //! @item +  //! Otherwise fall back to calling @[::report()] with the +  //! same arguments. +  //! @endul +  //! +  //! @note +  //! In Pike 8.0 and earlier @[MasterObject()->report()] was not called. +  //! +  //! @seealso +  //! @[Reporter()->report()] +  void report(SeverityLevel severity, string filename, int linenumber, +  string subsystem, +  sprintf_format message, sprintf_args ... extra_args) +  { +  foreach(({ handler, compat_handler }), object o) { +  if (!objectp(o)) continue; +  if (functionp(o->report)) { +  o->report(severity, filename, linenumber, +  subsystem, message, @extra_args); +  return; +  } +  if (severity < WARNING) continue; +  if (severity >= ERROR) { +  if (functionp(o->compile_error)) { +  o->compile_error(filename, linenumber, +  sizeof(extra_args)? +  sprintf(message, @extra_args): +  message); +  return; +  } +  } else { +  if (functionp(o->compile_warning)) { +  o->compile_warning(filename, linenumber, +  sizeof(extra_args)? +  sprintf(message, @extra_args): +  message); +  return; +  } +  } +  } +  ::report(severity, filename, linenumber, subsystem, message, @extra_args); +  } +  +  object get_compilation_handler(int major, int minor) +  { +  return apply_handler(__func__, major, minor); +  } +  + #if constant(_static_modules.Builtin.__HAVE_CPP_NO_HANDLERS__) +  mapping(string:string|function|object) get_predefines() +  { +  return apply_handler(__func__); +  } +  +  mixed resolv(string sym) +  { +  return apply_handler(__func__, sym, current_file, +  handler, compat_handler); +  } +  +  string handle_include(string header_file, string current_file, +  int(0..1) is_local_ref) +  { +  return apply_handler(__func__, header_file, current_file, +  is_local_ref); +  } +  +  string read_include(string filename) +  { +  return apply_handler(__func__, filename); +  } +  +  string decode_charset(string data, string charset) +  { +  return apply_handler(__func__, data, charset); +  } + #endif +  +  string evaluate_define(string def, string|void arguments) +  { +  return apply_handler(__func__, def, arguments); +  } +  +  void change_cpp_compatibility(int major, int minor) +  { +  if ((compat_major == major) && (compat_minor == minor)) { +  return; +  } +  +  if (((major == __REAL_MAJOR__) && (minor == __REAL_MINOR__)) || +  (major < 0)) { +  compat_handler = UNDEFINED; +  } else { +  compat_handler = get_compilation_handler(major, minor); +  } +  ::change_cpp_compatibility(major, minor); +  } +  +  int compile_exception(mixed err) +  { +  return apply_handler(__func__, err); +  } +  +  string format_exception(mixed err) +  { +  string ret = apply_handler(__func__, err); +  if (ret) return ret; +  if (compile_exception(err)) { +  return ""; +  } +  return 0; +  } +  + #if constant(_static_modules.Builtin.__HAVE_CPP_NO_HANDLERS__) +  +  protected void create(mapping(string:mixed) options) +  { +  // werror("CPP(%O)\n", options); +  handler = options->handler; +  compat_handler = UNDEFINED; +  ::create(options); +  } +  +  protected variant void create(string|void current_file, +  int|string|void charset, object|void handler, +  void|int compat_major, void|int compat_minor, +  void|int picky_cpp) +  { +  mapping(string:mixed) options = ([]); + #define CPP_OPT(X) do { if (X) { options->X = X; } } while(0) +  CPP_OPT(current_file); +  CPP_OPT(charset); +  CPP_OPT(handler); +  CPP_OPT(compat_major); +  CPP_OPT(compat_minor); +  CPP_OPT(picky_cpp); + #undef CPP_OPT +  local::create(options); +  } + #endif +  } + } +  + protected CompilerEnvironment DefaultCompilerEnvironment = +  CompilerEnvironment(); +  + protected string cpp(string data, mapping|string|void current_file, +  int|string|void charset, object|void handler, +  void|int compat_major, void|int compat_minor, +  void|int picky_cpp) + { +  CompilerEnvironment.CPP cpp_obj = +  DefaultCompilerEnvironment->CPP(current_file, charset, +  handler || UNDEFINED, +  compat_major, compat_minor, +  picky_cpp); +  +  cpp_obj->init_pike_cpp(); +  return cpp_obj->high_cpp(data); + } +    //! Compile the Pike code in the string @[source] into a program.   //! If @[filename] is not specified, it will default to @expr{"-"@}.   //!   //! Functionally equal to @expr{@[compile](@[cpp](@[source], @[filename]))@}.   //!   //! @seealso   //! @[compile()], @[cpp()], @[compile_file()]   //!   program compile_string(string source, void|string filename,    object|void handler,    void|program p,    void|object o,    void|int _show_if_constant_errors)   {   #ifdef RECUR_COMPILE_DEBUG    werror ("%*s>>> compile_string %O\n", GET_MSG_DEPTH, "", filename);    INC_MSG_DEPTH();   #endif -  program ret = compile(cpp(source, filename||"-", 1, handler, +  string code = cpp(source, filename||"-", 1, handler,    compat_major, compat_minor, -  (zero_type(_show_if_constant_errors)? +  (undefinedp(_show_if_constant_errors)?    show_if_constant_errors: -  _show_if_constant_errors)), +  _show_if_constant_errors)); +  program ret; +  if(code) +  ret = compile(code,    handler,    compat_major,    compat_minor,    p,    o);    if (source_cache)    source_cache[ret] = source;   #ifdef RECUR_COMPILE_DEBUG    DEC_MSG_DEPTH();    werror ("%*s<<< compile_string %O\n", GET_MSG_DEPTH, "", filename);   #endif    return ret;   }    -  + //! @endnamespace +  + //! Read a file from the master filesystem.   //! -  + //! The master filesystem defaults to the system filesystem, + //! but additional mountpoints may be added via + //! @[add_filesystem_handler()]. + //! + //! All file I/O performed by the @[MasterObject] is performed + //! via this function and its related functions. + //! + //! @seealso + //! @[add_filesystem_handler()], @[find_handler_for_path()], + //! @[master_get_dir()], @[master_file_stat()]   string master_read_file(string file)   { -  +  string x = find_handler_for_path(file); +  if(x) +  { +  object h = fs_map[x]; +  file = file[sizeof(x)+1..]; +  +  if(h = h->open(fakeroot(file),"r") ) +  { +  string q = ([function(void : string)]h->read)(); +  return q; +  } +  // TODO: should we be falling back here, or is this a hidden problem? +  } +     object o=Files()->Fd();    if( ([function(string, string : int)]o->open)(fakeroot(file),"r") )    return ([function(void : string)]o->read)();    return 0;   }      #ifdef GETCWD_CACHE   protected string current_path;   int cd(string s)   {    current_path=0;    return predef::cd(s);   }      string getcwd()   {    return current_path || (current_path=predef::getcwd());   }   #endif // GETCWD_CACHE    -  + constant high_master_get_dir = predef::get_dir; +    string combine_path_with_cwd(string ... paths)   {    return combine_path(IS_ABSOLUTE_PATH(paths[0])?"":getcwd(),@paths);   }      #ifdef FILE_STAT_CACHE      #define FILE_STAT_CACHE_TIME 20      int invalidate_time;   mapping(string:multiset(string)) dir_cache = ([]);         array(string) master_get_dir(string|void x)   { -  return get_dir(x); +  string y = find_handler_for_path(file); +  if(y) +  { +  object h = fs_map[y]; +  x = x[sizeof(y)+1..]; +  return h->get_dir(x);    } -  +  else return predef::get_dir(x); + }      Stat master_file_stat(string x)   { -  +  object y = find_handler_for_path(file); +     string dir = combine_path_with_cwd(x);    string file = BASENAME(dir);    dir = dirname(dir);       if(time() > invalidate_time)    {    dir_cache = ([]);    invalidate_time = time()+FILE_STAT_CACHE_TIME;    }       multiset(string) d = dir_cache[dir]; -  if( zero_type(d) ) +  if( undefinedp(d) )    {    array(string) tmp = master_get_dir(dir);    if(tmp)    {   #ifdef __NT__    tmp = map(tmp, lower_case);   #endif    d = dir_cache[dir] = (multiset)tmp;    }    else    dir_cache[dir]=0;    }      #ifdef __NT__    file = lower_case(file);   #endif    if(d && !d[file]) return 0;    -  return predef::file_stat(x); +  +  if(y) +  { +  object h = fs_map[y]; +  x = x[sizeof(y)+1..]; +  return h->stat(x);    } -  +  else return predef::file_stat(x); + }   #else - constant master_file_stat = predef::file_stat; - constant master_get_dir = predef::get_dir; + //constant master_file_stat = predef::file_stat; + //constant master_get_dir = predef::get_dir; +  + Stat master_file_stat(string file) + { +  string x = find_handler_for_path(file); +  if(x) +  { +  object h = fs_map[x]; +  file = file[sizeof(x)+1..]; +  +  return h->stat(file); +  } +  else return predef::file_stat(file); + } +  + array master_get_dir(string file) + { +  string x = find_handler_for_path(file); +  if(x) +  { +  object h = fs_map[x]; +  file = file[sizeof(x)+1..]; +  +  return h->get_dir(file); +  } +  else return predef::get_dir(file); + } +    #endif // FILE_STAT_CACHE    -  + //! mount a filesystem handler to be used by the resolver. on its own does noting, + //! but may be used with @[add_module_path] and friends to enable modules to be loaded + //! from Filesystem objects. + //! + //! @param mountpoint + //! the location in the filesystem to mount the handler + //! + //! @param filesystem + //! a filesystem object that will handle requests for the given mountpoint. + //! + //! @example + //! master()->add_filesystem_handler("/foo/bar.zip", Filesystem.Zip("/foo/bar.zip")); + //! master()->add_module_path("/foo/bar.zip/lib"); + //! + //! @seealso + //! @[find_handler_for_path()] + mixed add_filesystem_handler(string mountpoint, object /*Filesystem.Base*/ filesystem) + { +  mixed rv = fs_map[mountpoint]; +  fs_map[mountpoint] = filesystem; +  return rv; + }    -  + //! Return the mountpoint for the filesystem handler handling the + //! @[file] (if any). + //! + //! @seealso + //! @[add_filesystem_handler()] + string find_handler_for_path(string file) + { + // TODO: maybe some caching would be worthwhile here. maybe. +  +  foreach(reverse(sort(indices(fs_map))); int x; string path) +  { +  string p = path; +  if(p[-1] != '/') p+="/"; +  if(file[-1] != '/') file+="/"; +  if(has_prefix(file, p)) +  return path; +  } +  +  return 0; + } +    protected mapping(string:string) environment;      #ifdef __NT__   protected void set_lc_env (mapping(string:string) env)   {    environment = ([]);    foreach (env; string var; string val)    environment[lower_case (var)] = val;   }   #endif    -  + //! @namespace predef:: +    //! @decl mapping(string:string) getenv (void|int force_update)   //!   //! Queries the environment variables.   //!   //! @param force_update   //! A cached copy of the real environment is kept to make this   //! function quicker. If the optional flag @[force_update] is nonzero   //! then the real environment is queried and the cache is updated from   //! it. That can be necessary if the environment changes through other   //! means than @[putenv], typically from a C-level library.
pike.git/lib/master.pike.in:1309:   {    mapping(string:string) res;       if (force_update) {    res = Builtin._getenv();   #ifdef __NT__    set_lc_env (res);   #else    environment = res + ([]);   #endif -  // Kill the compat environment if forced. -  compat_environment = compat_environment_copy = 0; +     } -  +     else { -  if (compat_environment && -  !equal(compat_environment, compat_environment_copy)) { -  foreach(compat_environment; string varname; array(string) pair) { -  if (!equal(pair, compat_environment_copy[varname])) { -  putenv(pair[0], pair[1]); -  } -  } -  foreach(compat_environment_copy; string varname; array(string) pair) { -  if (!compat_environment[varname]) { -  putenv(pair[0]); -  } -  } -  } +    #ifdef __NT__    // Can't use the cached environment since variable names have been    // lowercased there.    res = Builtin._getenv();    if (!environment) set_lc_env (res);   #else    if (!environment) environment = Builtin._getenv();    res = environment + ([]);   #endif    }
pike.git/lib/master.pike.in:1376:   //! @seealso   //! @[putenv()]   variant string getenv (string varname, void|int force_update)   {    if (!environment || force_update) {   #ifdef __NT__    set_lc_env (Builtin._getenv());   #else    environment = Builtin._getenv();   #endif -  // Kill the compat environment if forced. -  compat_environment = compat_environment_copy = 0; +     }      #ifdef __NT__    varname = lower_case(varname);   #endif    -  if (compat_environment) { -  array(string) res; -  if (!equal(res = compat_environment[varname], -  compat_environment_copy[varname])) { -  // Something has messed with the compat environment mapping. -  putenv(varname, res[?1]); -  } -  } -  +     return environment[varname];   }      void putenv (string varname, void|string value)   //! Sets the environment variable @[varname] to @[value].   //!   //! If @[value] is omitted or zero, the environment variable   //! @[varname] is removed.   //!   //! @[varname] and @[value] cannot be wide strings nor contain
pike.git/lib/master.pike.in:1414:   //! @expr{'='@} characters.   //!   //! @note   //! On NT the environment variable name is case insensitive.   //!   //! @seealso   //! @[getenv()]   //!   {    Builtin._putenv (varname, value); -  if (compat_environment) { -  string lvarname = varname; - #ifdef __NT__ -  lvarname = lower_case(varname); - #endif -  if (value) { -  compat_environment[lvarname] = -  (compat_environment_copy[lvarname] = ({ varname, value })) + ({}); -  } else { -  m_delete(compat_environment, lvarname); -  m_delete(compat_environment_copy, lvarname); -  } -  } +     if (environment) {   #ifdef __NT__    varname = lower_case (varname);   #endif    if (value) environment[varname] = value;    else m_delete (environment, varname);    }   }       - //! @appears compile_file +    //! Compile the Pike code contained in the file @[filename] into a program.   //!   //! This function will compile the file @[filename] to a Pike program that can   //! later be instantiated. It is the same as doing   //! @expr{@[compile_string](@[Stdio.read_file](@[filename]), @[filename])@}.   //!   //! @seealso   //! @[compile()], @[compile_string()], @[cpp()]   //!   program compile_file(string filename,    object|void handler,    void|program p,    void|object o)   {    AUTORELOAD_CHECK_FILE(filename); -  return compile(cpp(master_read_file(filename), +  string code = cpp(master_read_file(filename),    filename,    1,    handler,    compat_major, -  compat_minor), +  compat_minor); +  if (!code) { +  error("Required feature missing.\n"); +  } +  return compile(code,    handler,    compat_major,    compat_minor,    p,    o);   }       - //! @appears normalize_path +    //! Replaces "\" with "/" if runing on MS Windows. It is   //! adviced to use @[System.normalize_path] instead.   string normalize_path( string path )   {   #ifndef __NT__    return path;   #else    return replace(path,"\\","/");   #endif   }    -  + //! @endnamespace +    //! Mapping containing the cache of currently compiled files.   //!   //! This mapping currently has the following structure:   //! @mapping   //! @member program filename   //! @endmapping   //! The filename path separator is / on both NT and UNIX.   //!   //! @note   //! Special cases: The current master program is available under the
pike.git/lib/master.pike.in:1517:   // doesn't work reliably there since it calls `==.   protected mapping(program:string) rev_programs = ([]);   protected mapping(object:program) rev_objects = ([]);   protected mapping(mixed:string) rev_fc = ([]);      string programs_reverse_lookup (program prog)   //! Returns the path for @[prog] in @[programs], if it got any.   {    // When running with trace, this function can get called    // before __INIT has completed. +  // NB: We need to be reasonably thread safe, as the compiler +  // may be running in another thread.    if (!rev_programs) return UNDEFINED;    if (sizeof (rev_programs) < sizeof (programs)) {    foreach (programs; string path; program|NoValue prog)    if (prog == no_value)    m_delete (programs, path);    else    rev_programs[prog] = path;    }    return rev_programs[prog];   }      program objects_reverse_lookup (object obj)   //! Returns the program for @[obj], if known to the master.   { -  +  // NB: We need to be reasonably thread safe, as the compiler +  // may be running in another thread.    if (sizeof (rev_objects) < sizeof (objects)) {    foreach (objects; program prog; object|NoValue obj)    if (obj == no_value)    m_delete (rev_objects, obj);    else    rev_objects[obj] = prog;    }    return rev_objects[obj];   }   
pike.git/lib/master.pike.in:1620:    array bt;    if (array|object e = catch (bt = get_backtrace (err)))    handle_error (e);    throw (CompileCallbackError (call_describe_error (err), bt));   }      protected void call_compile_warning (object handler, string file,    string msg, mixed ... args)   {    if (sizeof (args)) msg = sprintf (msg, @args); -  msg = trim_all_whites (msg); +  msg = trim (msg);    if (handler?->compile_warning)    handler->compile_warning (file, 0, msg);    else if (master()->compile_warning)    master()->compile_warning (file, 0, msg);    else    compile_warning (file, 0, msg);   }      #if constant(_static_modules.Builtin.mutex)   #define THREADED - _static_modules.Builtin.mutex compilation_mutex = Builtin.mutex(); +    #endif      #ifdef __NT__   #define FIX_CASE(X) lower_case(X)   #else   #define FIX_CASE(X) (X)   #endif /* __NT__ */      protected string base_from_filename(string fname)   {
pike.git/lib/master.pike.in:1665:   {    fname = FIX_CASE(fname);    if (has_suffix(fname, ".pmod")) return 3;    if (has_suffix(fname, ".so")) return 2;    if (has_suffix(fname, ".pike")) return 1;       // FIXME: Warn here?    return 0;   }    + protected bool is_joinnode(mixed o) + { +  return objectp(o) && object_program(o)->is_resolv_joinnode; + } +  + protected bool is_dirnode(mixed o) + { +  return objectp(o) && object_program(o)->is_resolv_dirnode; + } +    //! Find the files in which @[mod] is defined, as they may be hidden away in   //! joinnodes and dirnodes   //!   //! @param mod   //! The module we are looking for.   //!   //! @returns   //! An array of strings with filenames.   //! (one for each file in a joinnode, or just one otherwise)   array(string) module_defined(object|program mod)   {    array files = ({});    if (programp(mod))    return ({ Builtin.program_defined([program]mod) });       array mods; -  if (mod->is_resolv_joinnode) +  if (is_joinnode(mod))    mods = mod->joined_modules;    else    mods = ({ mod });       foreach (mods;; object mod)    { -  if (mod->is_resolv_dirnode) +  if (is_dirnode(mod))    files += ({ Builtin.program_defined(object_program(mod->module)) });    else    files += ({ Builtin.program_defined(object_program(mod)) });    }    return files;   }      //! Enable caching of sources from compile_string()   void enable_source_cache()   {
pike.git/lib/master.pike.in:1725:       if (programp(obj))    prog = obj;    if (functionp(obj))    {    prog = function_program(obj);    child = ((describe_function(obj)||"")/"->")[-1];    }    if (objectp(obj))    { -  if (obj->is_resolv_joinnode) +  if (is_joinnode(obj))    obj = obj->joined_modules[0]; // FIXME: check for multiples -  if (obj->is_resolv_dirnode) +  if (is_dirnode(obj))    prog = object_program(obj->module);    else    prog = object_program(obj);    }          if (prog && !documentation[prog] && doc_extractor)    {    string source;    if (source_cache && source_cache[prog])
pike.git/lib/master.pike.in:1795:    object|void handler,    void|int mkobj)   {    program ret;    Stat s;    string fname=pname+ext;       resolv_debug("low_findprog(%O, %O, %O, %O)\n",    pname, ext, handler, mkobj);    - #ifdef THREADED -  object key; -  // The catch is needed, since we might be called in a context when -  // threads are disabled. (compile() disables threads). -  mixed err = catch { -  key=compilation_mutex->lock(2); -  }; -  if (err && !has_suffix (err[0], "when threads are disabled!")) -  throw (err); - #endif -  +    #ifdef PIKE_MODULE_RELOC    fname = unrelocate_module(fname);   #endif      #ifdef __NT__    // Ugly kluge to work better with cygwin32 "/X:/" paths.    if(getenv("OSTYPE")=="cygwin32")    {    string tmp=fname[..1];    if((tmp=="//" || tmp=="\\\\") && (fname[3]=='/' || fname[3]=='\\'))
pike.git/lib/master.pike.in:1831:    }    }   #endif       if( (s=master_file_stat(fakeroot(fname))) && s->isreg )    {   #ifdef PIKE_AUTORELOAD    if(!autoreload_on || load_time[fname] >= s->mtime)   #endif    { -  if(!zero_type (ret=programs[fname]) && ret != no_value) { +  if(!undefinedp (ret=programs[fname]) && ret != no_value) {    resolv_debug ("low_findprog %s: returning cached (no autoreload)\n", fname);    return ret;    }    }       AUTORELOAD_BEGIN();      #ifdef PIKE_AUTORELOAD    if (load_time[fname] >= s->mtime) -  if (!zero_type (ret=programs[fname]) && ret != no_value) { +  if (!undefinedp (ret=programs[fname]) && ret != no_value) {    resolv_debug ("low_findprog %s: returning cached (autoreload)\n", fname);    return ret;    }   #endif    -  +  object compiler_lock = DefaultCompilerEnvironment->lock(); +  if(!undefinedp(ret = programs[fname]) && (ret != no_value)) { +  destruct(compiler_lock); +  resolv_debug("low_findprog %s: returning cached (from other thread).\n", +  fname); +  return ret; +  } +     switch(ext)    {    case "":    case ".pike":    foreach(query_precompiled_names(fname), string oname) {    int o_mtime = get_precompiled_mtime (oname);    if (o_mtime >= 0) {    if (o_mtime >= s->mtime) {    mixed err=catch {    object|program decoded;
pike.git/lib/master.pike.in:1918:    if ( mixed e=catch {    ret=compile_string(src, fname, handler,    ret,    mkobj? (objects[ret]=__null_program()) : 0);    } )    {    DEC_RESOLV_MSG_DEPTH();    resolv_debug ("low_findprog %s: compilation failed\n", fname);    objects[ret] = no_value;    ret=programs[fname]=0; // Negative cache. +  destruct(compiler_lock);    throw(e);    } -  +  destruct(compiler_lock);    DEC_RESOLV_MSG_DEPTH();    resolv_debug ("low_findprog %s: compilation ok\n", fname);    break;      #if constant(load_module)    case ".so":    if (fname == "") {    werror( "low_findprog(%O, %O) => load_module(\"\")\n"    "%s\n", pname, ext, call_describe_backtrace(backtrace()) );    }
pike.git/lib/master.pike.in:1963:   #endif /* load_module */    }       AUTORELOAD_FINISH(ret,programs,fname);       if (ret?->this_program_does_not_exist) {    resolv_debug ("low_findprog %s: program says it doesn't exist\n", fname);    return programs[fname] = 0;    }    else { +  if(!ret) +  resolv_debug("low_findprog %s: dependencies failed.\n", fname); +  else    resolv_debug("low_findprog %s: returning %O\n", fname, ret);    return programs[fname]=ret;    }    }       resolv_debug ("low_findprog %s: file not found\n", fname);    return 0;   }      //   // This function is called by the compiler when a delayed compilation   // error occurs in the given program. It should remove all references   // to the program so that it can be freed.   //   void unregister(program p)   {    // werror("Unregistering %O...\n", p); -  +  object compiler_lock = DefaultCompilerEnvironment->lock(); +     if(string fname=rev_programs[p] || search(programs,p)) {    resolv_debug("unregister %s\n", fname);    if (m_delete (rev_programs, p))    m_delete (programs, fname);    else    programs[fname] = no_value;       string name = program_path_to_name (fname); -  mixed n = has_value (name, ".") ? +  mixed n = has_value (name, '.') ?    resolv ((name / ".")[..<1] * ".") :    get_root_module(); -  if (objectp (n) && (n->is_resolv_dirnode || n->is_resolv_joinnode)) +  if (is_dirnode(n) || is_joinnode(n))    n->delete_value (p);       fname = dirname (fname);    if ( fname!="" && objectp (n = fc[fname]) ) -  if (n->is_resolv_dirnode) // Won't find joinnodes in fc. +  if (is_dirnode(n)) // Won't find joinnodes in fc.    n->delete_value (p);    }       object o = m_delete(objects, p);    if (objectp (o)) {    m_delete(rev_objects, o);    }       foreach (fc; string name; mixed mod)    if (objectp(mod) && object_program(mod) == p)
pike.git/lib/master.pike.in:2055:       if(sscanf(reverse(BASENAME(pname)),"%s.%s",ext, nname))    {    ext="."+reverse(ext);    pname=pname[..<sizeof(ext)];    }    else {    ext="";    }    +  // NB: No need to lock the compiler here; findprog() will +  // lock and reprobe on miss in the programs mapping.    if(IS_ABSOLUTE_PATH(pname))    {    program|NoValue prog = programs[pname]; -  if ((!zero_type(prog)) && (prog != no_value)) +  if ((!undefinedp(prog)) && (prog != no_value))    {    return prog;    }    pname=combine_path("",pname);    return findprog(pname,ext,handler,mkobj);    }    else {    string cwd;    if(current_file)    {
pike.git/lib/master.pike.in:2155:    };    werror(narrowify_string(sprintf("Original error:\n"    "%O\n", trace)));    }) {    werror("sprintf() failed to write error.\n");    }    }    // predef::trace(0);   }    + //! This function is called in runtime check_types mode (@tt{-rt@}), + //! when encountering a soft cast to an attributed type. + //! + //! @param value + //! Value that is about to receive the attribute. + //! + //! @param attribute + //! Type attribute to validate. + //! + //! @returns + //! Returns one of: + //! @int + //! @value 1 + //! If the attribute is valid for the value. + //! @value 0 + //! If the attribute is not valid for the value. + //! @value UNDEFINED + //! If the attribute is unsupported. + //! @endint + //! + //! The default master implements validation of the @expr{"utf8"@} + //! attribute. + optional int(0..1) handle_attribute(mixed value, string attribute) + { +  switch(attribute) { + #if constant(validate_utf8) +  case "utf8": +  return stringp(value) && validate_utf8(value, 3); + #endif +  } +  return UNDEFINED; + } +    /* This array contains the names of the functions    * that a replacing master-object may want to override.    */   constant master_efuns = ({    "error",    "basename",    "dirname",    "is_absolute_path",    "explode_path",   
pike.git/lib/master.pike.in:2177:    "add_include_path",    "remove_include_path",    "add_module_path",    "remove_module_path",    "add_program_path",    "remove_program_path",    "describe_backtrace",    "describe_error",    "get_backtrace",    "normalize_path", -  "bool", +     "true",    "false",    "getenv",    "putenv",      #ifdef GETCWD_CACHE    "cd",    "getcwd",   #endif   });    - enum bool { false=0, true=1 }; -  +    //! Prefix for Pike-related C header files.   string include_prefix;      //! Prefix for autodoc files.   string doc_prefix;      //! Flags suitable for use when compiling Pike C modules   string cflags;      //! Flags suitable for use when linking Pike C modules   string ldflags; // Not yet used    - //! @decl int strlen(string|multiset|array|mapping|object thing) - //! @appears strlen - //! Alias for @[sizeof]. - //! @deprecated sizeof + //! @namespace predef:: + //! + //! This is the default namespace and contains lots of global symbols.    -  + //! Boolean datatype. + enum bool { false=0, true=1 }; +    //! @decl int write(string fmt, mixed ... args) - //! @appears write +    //! Writes a string on stdout. Works just like @[Stdio.File.write]   //! on @[Stdio.stdout].      //! @decl int werror(string fmt, mixed ... args) - //! @appears werror +    //! Writes a string on stderr. Works just like @[Stdio.File.write]   //! on @[Stdio.stderr].    -  + //! @decl array random(mapping m) + //! @decl float random(float max) + //! @decl int random(int max) + //! @decl mixed random(object o) + //! @decl mixed random(array|multiset x) + //! + //! Get a random value generated by the default @[RandomSystem]. + //! + //! @seealso + //! @[RandomSystem()->random()], @[random_string()] +  + //! @decl string random_string(int len) + //! + //! Get a string of random characters @expr{0..255@} with the length @[len] + //! from the default @[RandomSystem]. + //! + //! @seealso + //! @[RandomSystem()->random_string()], @[random()] +  + //! @decl int cp(string from, string to) + //! + //! Copies the file @[from] to the new position @[to]. This is an + //! alias for @[Stdio.cp]. +    /* Note that create is called before add_precompiled_program    */   protected void create()   { -  +  add_constant("CompilerEnvironment", CompilerEnvironment); +  add_constant("DefaultCompilerEnvironment", DefaultCompilerEnvironment); +  add_constant("cpp", cpp); +     foreach(master_efuns, string e) -  if (!zero_type(this[e])) +  if (has_index(this, e))    add_constant(e, this[e]);    else    error("Function %O is missing from master.pike.\n", e);    -  +  + // This gives the type int(0..1), which is more close to reality + // than the enum type (aka int(1..1)) + // + // doing the add_constant on the typeof directly gives int(1..1) + // instead, since the same "optimization" of the type is done in that + // case. +  add_constant("bool", typeof([int(0..1)](mixed)0)); +     add_constant("__dirnode", dirnode);    add_constant("__joinnode", joinnode);       add_constant("write", write);    add_constant("werror", werror);    // To make it possible to overload get_dir and file_stat later on.    // It's not possible to replace efuns with normal functions in .o-files    -  add_constant("get_dir", master_get_dir ); +  add_constant("get_dir", high_master_get_dir );    add_constant("file_stat", lambda( string f, int|void d ) { return file_stat(f,d);} );    -  +  object rnd = Builtin.RandomSystem(); +  add_constant("random", rnd->random); +  add_constant("random_string", rnd->random_string); +    #define CO(X) add_constant(#X,Builtin.__backend->X)    CO(call_out);    CO(_do_call_outs);    CO(find_call_out);    CO(remove_call_out);    CO(call_out_info);      #if "#share_prefix#"[0]!='#'    // add path for architecture-independant files    add_include_path("#share_prefix#/include");
pike.git/lib/master.pike.in:2283:   #endif      #if constant(__embedded_resource_directory)    // for use with embedded interpreters    // add path for architecture-dependant files    add_include_path(__embedded_resource_directory + "/lib/include");    add_module_path(__embedded_resource_directory + "/lib/modules");    add_module_path(__embedded_resource_directory + "/" + replace(uname()->machine, " ", "_") + "/modules");      #endif -  +     system_module_path=pike_module_path;   }    -  + //! @endnamespace      //! This function is called whenever a inherit is called for.   //! It is supposed to return the program to inherit.   //! The first argument is the argument given to inherit, and the second   //! is the file name of the program currently compiling. Note that the   //! file name can be changed with #line, or set by compile_string, so   //! it can not be 100% trusted to be a filename.   //! previous_object(), can be virtually anything in this function, as it   //! is called from the compiler.   program handle_inherit(string pname, string current_file, object|void handler)
pike.git/lib/master.pike.in:2314:   }      object low_cast_to_object(string oname, string current_file,    object|void current_handler)   {    program p;    object o;       p = low_cast_to_program(oname, current_file, current_handler, 1);    if(!p) return 0; +  if(!objectp(o = objects[p])) { +  object compiler_lock = DefaultCompilerEnvironment->lock();    // NB: p might be a function in a fake_object... -  if(!objectp (o=objects[p])) o=objects[p]=p(); +  if(!objectp(o = objects[p])) o = objects[p] = p(); +  destruct(compiler_lock); +  }    return o;   }      //! This function is called when the drivers wants to cast a string   //! to an object because of an implict or explicit cast. This function   //! may also receive more arguments in the future.   object cast_to_object(string oname, string current_file,    object|void current_handler)   {    resolv_debug ("cast_to_object(%O, %O)\n", oname, current_file);
pike.git/lib/master.pike.in:2354:   //! @seealso   //! @[joinnode]   class dirnode (string dirname, object|void compilation_handler,    string|void name)   {    constant is_resolv_dirnode = 1;    // objectp() is intentionally not used on the module object, to    // allow a module to deny its own existence with `!.    mixed module;    mapping(string:mixed) cache=([]); -  mapping(string:array(string)) file_paths = ([]); +     -  +  // Maps a base name like "Bar" to an ordered array of file paths, +  // e.g. ({ "/lib/Foo.pmod/Bar.pmod", "/lib/Foo.pmod/Bar.so" }). +  protected mapping(string:array(string)) file_paths = ([]); +    #ifdef __NT__   #define FIX_CASE(X) lower_case(X)   #else   #define FIX_CASE(X) (X)   #endif /* __NT__ */       protected string base_from_filename(string fname)    {    string low_name = FIX_CASE(fname);    catch {
pike.git/lib/master.pike.in:2395:    }    return 0;    }       protected int prio_from_filename(string fname)    {    fname = FIX_CASE(fname);    if (has_suffix(fname, ".pmod")) return 3;    if (has_suffix(fname, ".so")) return 2;    if (has_suffix(fname, ".pike")) return 1; -  -  // FIXME: Warn here? -  return 0; +  return 0; // We will not reach this.    }       protected void create()    { -  +  if (!dirname) { +  error("Attempt to create a dirnode without a directory.\n" +  "Have you inherited a dirnode?\n"); +  } +     resolv_debug ("dirnode(%O,%O) created with name %O\n", dirname,    compilation_handler, name);    fc[dirname]=this; -  array(string) files = sort(master_get_dir(dirname)||({})); +     if (!sizeof(dirname)) return; -  +  array(string) files = sort(master_get_dir(dirname)||({}));    array(string) bases = map(files, base_from_filename);    files = filter(files, bases);    bases = filter(bases, bases);    resolv_debug("dirnode(%O,%O) got %d files.\n",    dirname, compilation_handler, sizeof(bases));    if (!sizeof(files)) return;       foreach(files; int no; string fname) {    fname = combine_path(dirname, fname);    string base = bases[no];
pike.git/lib/master.pike.in:2439:    // Insert sort. Worst case is 3 filenames.    int prio = prio_from_filename(fname);    int index;    foreach(paths; index; string other_fname) {    if (prio_from_filename(other_fname) <= prio) break;    }    file_paths[base] = paths[..index-1] + ({ fname }) + paths[index..];    }    }    -  class module_checker +  protected class module_checker    {    protected int `!()    {    resolv_debug ("dirnode(%O)->module_checker()->`!()\n",dirname);       if (mixed err = catch {    // Look up module.    if (module = cache["module"] || low_ind("module", 1)) {    /* This allows for `[] to have side effects first time    * it is called. (Specifically, the Calendar module uses
pike.git/lib/master.pike.in:2557:    if (ret = low_cast_to_program(fname, 0, compilation_handler)) {    DEC_RESOLV_MSG_DEPTH();    resolv_debug("dirnode(%O)->ind(%O) => found subprogram %O:%O\n",    dirname, index, fname, ret);   #if constant(load_module)    if (has_suffix(fname, ".so")) {    // This is compatible with 7.4 behaviour.    if (!ret->_module_value) {    object o;    // NB: p might be a function in a fake_object... -  if(!objectp (o=objects[ret])) o=objects[ret]=ret(); +  if(!objectp(o = objects[ret])) { +  object compiler_lock = DefaultCompilerEnvironment->lock(); +  if(!objectp(o = objects[ret])) o = objects[ret] = ret(); +  destruct(compiler_lock); +  }    ret = o;    }    if(mixed tmp=ret->_module_value) ret=tmp;    }   #endif    return ret;    }    }    resolv_debug("dirnode(%O)->ind(%O) => failure for file %O\n",    dirname, index, fname);
pike.git/lib/master.pike.in:2590:    if (_cache_full) {    DEC_RESOLV_MSG_DEPTH();    resolv_debug("dirnode(%O)->ind(%O) => cache_full %O\n",    dirname, index, cache[index]);    return cache[index];    }       if(module)    {    mixed o; - // _describe(module); -  if(!zero_type(o=module[index])) +  if(!undefinedp(o=module[index]))    {    DEC_RESOLV_MSG_DEPTH();    resolv_debug ("dirnode(%O)->ind(%O) => found %O\n",    dirname, index, o);    return o;    }    resolv_debug ("dirnode(%O)->ind(%O) => not found in module\n",    dirname, index);    }    else    resolv_debug ("dirnode(%O)->ind(%O) => no module\n", dirname, index);       DEC_RESOLV_MSG_DEPTH();    return low_ind(index);    }    -  +  protected mixed `[]=(string index, mixed value) +  { +  if(module && has_index(module, index)) +  return module[index]=value,cache[index]=value; +  error("No such variable (%s) in object.\n", index); +  } +  +  protected mixed `->=(string index, mixed value) +  { +  return `[]=(index, value); +  } +     protected mixed `[](string index)    {    mixed ret;   #ifdef MODULE_TRACE    werror("%*nDirnode(%O) cache[%O] ?????\n",    sizeof(backtrace()),dirname,index);   #endif -  if(!zero_type(ret=cache[index])) +  if(!undefinedp(ret=cache[index]))    {   #ifdef MODULE_TRACE    werror("%*nDirnode(%O) cache[%O] => %O%s\n",    sizeof(backtrace()),dirname,index, ret,    (ret != ZERO_TYPE)?"":" (zero_type)");   #endif    if (ret != ZERO_TYPE) return ret;   #ifdef MODULE_TRACE    werror("%*nDirnode(%O) ZERO_TYPE!\n",    sizeof(backtrace()),dirname);
pike.git/lib/master.pike.in:2641:    // We might have gotten placeholder objects in the first pass    // which must not be cached to the second.    if(ret == predef::__placeholder_object) {   #ifdef MODULE_TRACE    werror("%*nDirnode(%O) PLACE_HOLDER.\n",    sizeof(backtrace()),dirname);   #endif    return ret;    }    -  cache[index] = zero_type(ret) ? ZERO_TYPE : ret; +  cache[index] = undefinedp(ret) ? ZERO_TYPE : ret;    return ret;    }    -  mixed safe_index(string index) +  protected mixed `->(string index)    { -  +  if( (< "dirname", "name", "is_resolv_dirnode", +  "module", "delete_value" >)[index] ) +  return ::`->(index); +  return `[](index); +  } +  +  protected mixed safe_index(string index) +  {    mixed err;    resolv_debug ("dirnode(%O): %O...\n", dirname, index);    if (err = catch { return `[](index); }) {    call_compile_warning (compilation_handler,    dirname+"."+fname,    "Compilation failed: " +    call_describe_error(err));    }    return UNDEFINED;    }       protected int(0..1) _cache_full; -  void fill_cache() +  protected void fill_cache()    { - #if 0 -  werror(call_describe_backtrace(({ sprintf("Filling cache in dirnode %O\n", -  dirname), -  backtrace() }))); - #endif +     if (_cache_full) {    return;    }       resolv_debug ("dirnode(%O) => Filling cache...\n", dirname);       // NOTE: We rely on side effects in `[]() and safe_index()    // to fill the cache.       // Why shouldn't thrown errors be propagated here? /mast
pike.git/lib/master.pike.in:2688:    dirname, module, indices(module));    map(indices(module), safe_index);    }       map(indices(file_paths), safe_index);    _cache_full = (object_program(module) != __null_program);    resolv_debug ("dirnode(%O) => Cache %s.\n", dirname,    _cache_full?"full":"partially filled");    }    -  protected protected array(string) _indices() +  protected array(string) _indices()    {    fill_cache();    // Note: Cannot index cache at all here to filter out the    // ZERO_TYPE values since that can change the order in the    // mapping, and _indices() has to return the elements in the same    // order as a nearby _values() call.    return filter (indices (cache), map (values (cache), `!=, ZERO_TYPE));    }    -  protected protected array(mixed) _values() +  protected array(mixed) _values()    {    fill_cache();    return values(cache) - ({ZERO_TYPE});    }       void delete_value (mixed val)    {    if (string name = search (cache, val)) {    m_delete (cache, name);    _cache_full = 0;
pike.git/lib/master.pike.in:2741:    string|void name)   {    constant is_resolv_joinnode = 1;       mapping(string:mixed) cache=([]);       protected string _sprintf(int as)    {    if (as != 'O') return 0;    if (name) { -  if (has_value (name, "|")) +  if (has_value (name, '|'))    return "joinnode(" + name + ")";    else    return name; // Let's be brief.    }    else    return sprintf("master()->joinnode(%O)", joined_modules);    }       protected void create()    {    if( !fallback_module ) {    // NOTE: Uses the empty mapping as the default fallback    // for simplified code.    fallback_module = ([]);    }    -  +  if (!joined_modules) { +  error("Attempt to create a joinnode without joined modules.\n" +  "Have you inherited a joinnode?\n"); +  } +     if (!name)    {    mapping(string:int(1..1)) names = ([]);    foreach (joined_modules, object|mapping m) {    if (objectp (m) && stringp (m->name))    names[m->name] = 1;    }    if (sizeof (names))    name = sort (indices (names)) * "|";    }       resolv_debug ("joinnode(%O) created with name %O\n", joined_modules, name);    }       void add_path(string path)    {    path = combine_path(getcwd(), path);    dirnode node = fc[path] ||    (fc[path] = dirnode(path, compilation_handler, -  name && !has_value (name, "|") && name)); +  name && !has_value (name, '|') && name));    if (sizeof(joined_modules) &&    joined_modules[0] == node) return;    joined_modules = ({ node }) + (joined_modules - ({ node }));    cache = ([]);    }       void rem_path(string path)    {    path = combine_path(getcwd(), path);    joined_modules = filter(joined_modules,    lambda(dirnode node) { -  return !objectp(node) || -  !node->is_resolv_dirnode || +  return !is_dirnode(node) ||    (node->dirname != path);    });    cache = ([]);    }       protected mixed ind(string index)    {    resolv_debug ("joinnode(%O)->ind(%O)\n", joined_modules, index);    INC_RESOLV_MSG_DEPTH();       array(mixed) res = ({});    foreach(joined_modules, object|mapping o)    {    mixed ret; -  if (!zero_type(ret = o[index])) +  if (!undefinedp(ret = o[index]))    { -  if (objectp(ret) && -  (ret->is_resolv_dirnode || ret->is_resolv_joinnode)) +  if (is_dirnode(ret) || is_joinnode(ret))    {    // Only join directorynodes (or joinnodes).    res += ({ ret });    } else {    DEC_RESOLV_MSG_DEPTH();    resolv_debug ("joinnode(%O)->ind(%O) => found %O\n",    joined_modules, index, ret);    return (ret);    }    }    }       if (sizeof(res)) {    DEC_RESOLV_MSG_DEPTH();    resolv_debug("joinnode(%O)->ind(%O) => new joinnode, fallback: %O\n",    joined_modules, index, fallback_module[index]);    return joinnode(res, compilation_handler, fallback_module[index], -  name && !has_value (name, "|") && +  name && !has_value (name, '|') &&    (name == "predef::" ? index : name + "." + index));    }       DEC_RESOLV_MSG_DEPTH();    resolv_debug ("joinnode(%O)->ind(%O) => not found. Trying fallback %O\n",    joined_modules, index, fallback_module);    return fallback_module[index];    }    -  +  protected mixed `[]=(string index, mixed value) +  { +  foreach(joined_modules, object|mapping o) +  if(has_index(o, index)) +  return o[index]=value,cache[index]=value; +  error("No such variable (%s) in object.\n", index); +  } +  +  protected mixed `->=(string index, mixed value) +  { +  if( index=="fallback_module" ) +  return fallback_module=value; +  return `[]=(index, value); +  } +     protected mixed `[](string index)    {    mixed ret; -  if (!zero_type(ret = cache[index])) { +  if (!undefinedp(ret = cache[index])) {    if (ret != ZERO_TYPE) {    return ret;    }    return UNDEFINED;    }    ret = ind(index);       // We might have gotten placeholder objects in the first pass    // which must not be cached to the second.    if(ret == predef::__placeholder_object) return ret;    -  if (zero_type(ret)) { +  if (undefinedp(ret)) {    cache[index] = ZERO_TYPE;    } else {    cache[index] = ret;    }    return ret;    }    -  +  protected mixed `->(string index) +  { +  if( (< "joined_modules", "fallback_module", "name", "is_resolv_joinnode", +  "add_path", "rem_path", "delete_value", "_encode", +  "_decode" >)[index] ) +  return ::`->(index); +  return `[](index); +  } +     protected int _cache_full;    -  void fill_cache() +  protected void fill_cache()    { - #if 0 -  werror(call_describe_backtrace(({ "Filling cache in joinnode\n", -  backtrace() }))); - #endif +     if (_cache_full) {    return;    }    foreach(joined_modules, object|mapping|program o) {    foreach(indices(o), string index) { -  if (zero_type(cache[index])) { +  if (!has_index(cache, index)) {    `[](index);    }    }    }    foreach(indices(fallback_module), string index) {    `[](index);    }    _cache_full = 1;    }   
pike.git/lib/master.pike.in:2899:    // order as a nearby _values() call.    return filter (indices (cache), map (values (cache), `!=, ZERO_TYPE));    }       protected array(mixed) _values()    {    fill_cache();    return values(cache) - ({ZERO_TYPE});    }    +  protected int(0..) _sizeof() +  { +  return sizeof(_values()); +  } +     void delete_value (mixed val)    {    if (string name = search (cache, val))    m_delete (cache, name);    for (int i = 0; i < sizeof (joined_modules); i++) {    object|mapping|program o = joined_modules[i];    if (o == val) {    joined_modules = joined_modules[..i - 1] + joined_modules[i + 1..];    i--;    } -  else if (objectp (o) && (o->is_resolv_dirnode || o->is_resolv_joinnode)) +  else if (is_dirnode(o) || is_joinnode(o))    o->delete_value (val);    else if (string name = mappingp (o) && search (o, val))    m_delete (o, name);    }    }       protected int `== (mixed other)    { -  return objectp (other) && (other->is_resolv_joinnode == 1) && +  // NB: Index the program instead of the object to avoid issues +  // with modules overloading lfun::`->() with stuff that has +  // side-effects (here's looking at you Calendar.Events). +  return is_joinnode(other) &&    equal (mkmultiset (joined_modules), mkmultiset (other->joined_modules));    }       array(object) _encode()    {    return joined_modules;    }       void _decode (array(object) joined_modules)    { -  this_program::joined_modules = joined_modules; +  this::joined_modules = joined_modules;    }   }      joinnode handle_import(string path, string|void current_file,    object|void current_handler)   { - #ifdef __amigaos__ -  if(path == ".") -  path = ""; - #endif +     if(current_file)    {    path = combine_path_with_cwd(dirname(current_file), path);    } else {    path = combine_path_with_cwd(path);    }       // FIXME: Need caching!!!   #if 0    // FIXME: This caching strategy could be improved,
pike.git/lib/master.pike.in:2985:    node->add_path(path);    return node;   }      program|object findmodule(string fullname, object|void handler,    void|string name)   {    program|object o;       resolv_debug ("findmodule(%O)\n", fullname); -  if(!zero_type(o=fc[fullname]) && o != no_value) +  if(!undefinedp(o=fc[fullname]) && o != no_value)    {    if (objectp(o) || programp(o) || o != 0) {    resolv_debug ("findmodule(%O) => found %O (cached)\n", fullname, o);    return o;    }    resolv_debug ("findmodule(%O) => not found (cached)\n", fullname);    return UNDEFINED;    }       if(Stat stat=master_file_stat(fakeroot(fullname)))
pike.git/lib/master.pike.in:3055:    // module dumping. /mast    if (handler) {    resolv_debug ("handle_import(%O, %O, %O) => new dirnode with handler\n",    what, current_file, handler);    return dirnode(path, handler);    }   #endif       if(objectp (fc[path])) {    resolv_debug ("handle_import(%O, %O) => found %O (cached)\n", +  object s = file_stat(tmp); +  if(s && s->isreg) +  { +  object fs; +  catch(fs = resolv("Filesystem.Zip")(tmp)); +  if(fs) add_filesystem_handler(tmp, fs); +  tmp = combine_path(tmp, "include"); +  }    what, current_file, fc[path]);    return fc[path];    }    resolv_debug ("handle_import(%O, %O) => new dirnode\n", what, current_file);   #ifdef PIKE_MODULE_RELOC    // If we have PIKE_MODULE_RELOC enabled,    // we might need to map to a join node.    // FIXME: Ought to use the non-relocate_module() fakeroot().    if(path == "/${PIKE_MODULE_PATH}" ||    has_prefix(path, "/${PIKE_MODULE_PATH}/")) {    string tmp = path[21..];    array(dirnode) dirnodes = ({});    foreach(pike_module_path, string prefix) {    string s2 = fakeroot(sizeof(tmp)? combine_path(prefix, tmp) : prefix); -  +  +  // do we have a mounted zip? +  if(fs_map[tmp]) +  tmp = combine_path(tmp, "modules"); +     if(master_file_stat(s2))    dirnodes += ({ dirnode(s2, handler) });    }    resolv_debug("handle_import(%O, %O) => Found %d dirnodes\n",    what, current_file, sizeof(dirnodes));    if (sizeof(dirnodes) > 1) return fc[path] = joinnode(dirnodes);    if (sizeof(dirnodes)) return fc[path] = dirnodes[0];    return UNDEFINED;    }   #endif /* PIKE_MODULE_RELOC */    return fc[path] = dirnode(fakeroot(path), handler);   }   #endif /* 0 */    -  +    multiset no_resolv = (<>);      //! Resolver of symbols not located in the program being compiled.   class CompatResolver   {    //! Join node of the root modules for this resolver.    joinnode root_module =    joinnode(({instantiate_static_modules(predef::_static_modules)}),    0, 0, "predef::");   
pike.git/lib/master.pike.in:3175:    pike_include_path-=({tmp});    }       //! Add a directory to search for modules.    //!    //! This is the same as the command line option @tt{-M@}.    //!    //! @seealso    //! @[remove_module_path()]    //! -  void add_module_path(string tmp) +  //! @param path +  //! a string containing a path to search for Pike modules. May be a +  //! directory, or a path to a ZIP archive. If a ZIP archive path is +  //! provided, modules will be loaded from a directory, "modules" within +  //! the ZIP archive (see the subpath argument). +  //! +  //! @param subpath +  //! if path is a ZIP archive, this argument will determine the path within +  //! the archive to be searched. +  //! +  void add_module_path(string path, string|void subpath)    { -  tmp=normalize_path(combine_path_with_cwd(tmp)); -  root_module->add_path(tmp); -  pike_module_path = ({ tmp }) + (pike_module_path - ({ tmp })); +  path=normalize_path(combine_path_with_cwd(path)); +  +  object s = file_stat(path); +  if(s && s->isreg) +  { +  object fs; +  catch(fs = resolv("Filesystem.Zip")(path)); +  if(fs) add_filesystem_handler(path, fs); +  if(!subpath) subpath = "modules"; +  path = combine_path(path, subpath);    }    -  +  root_module->add_path(path); +  pike_module_path = ({ path }) + (pike_module_path - ({ path })); +  } +     //! Remove a directory to search for modules.    //!    //! This function performs the reverse operation of @[add_module_path()].    //!    //! @seealso    //! @[add_module_path()]    //!    void remove_module_path(string tmp)    {    tmp=normalize_path(combine_path_with_cwd(tmp));
pike.git/lib/master.pike.in:3243:    {    m_delete (predefines, name);    }       //! Returns a mapping with the current predefines.    mapping get_predefines()    {    return predefines;    }    -  string evaluate_define(string def, string arguments) -  { -  mixed val = arguments ? predefines[def+"()"] : predefines[def]; -  if( callablep(val) ) -  { -  object C = resolv("Parser.C"); -  array args; -  if( arguments ) -  args = map( -  map(C.group(C.split(arguments))/({","}),C.simple_reconstitute), -  resolv("String.trim_all_whites")); -  else -  args = ({}); -  -  val = val( @args ); -  } -  return (string)val; -  } -  +     //! Instantiate static modules in the same way that dynamic modules    //! are instantiated.    protected mapping(string:mixed) instantiate_static_modules(object|mapping static_modules)    {    mapping(string:mixed) res = ([]), joins = ([]);    foreach(indices(static_modules), string name) {    mixed val = static_modules[name];    if (!val->_module_value)    val = val();    if(mixed tmp=val->_module_value) val=tmp;
pike.git/lib/master.pike.in:3300:    if(mappingp(v))    v = joinify(v);    if(res[n])    res[n] = joinnode(({res[n], v}), 0, 0, n);    else    res[n] = v;    }    return res;    }    +  //! Return the default module for the @[CompatResolver].    //! -  +  //! This is the mapping that corresponds to the @[predef::] +  //! name space for the compatibility level, and is the +  //! value returned by @[all_constants()] for the same.    mapping get_default_module()    {    resolv_debug ("%O->get_default_module()\n", this);    -  /* This is an ugly kluge to avoid an infinite recursion. -  * The infinite recursion occurs because this function is -  * called for every file when the compat_major/minor is set. -  * This kluge could cause problems with threads if the -  * compiler was threaded. -Hubbe +  /* This is an ugly kluge to avoid an infinite recursion. The +  * infinite recursion occurs because this function is called for +  * every file when the compat_major/minor is set. This kluge +  * could cause problems with threads if the compiler was +  * threaded. -Hubbe    */    int saved_compat_minor=compat_minor;    int saved_compat_major=compat_major;    compat_minor=-1;    compat_major=-1;       mixed x;    mixed err =catch {    if(resolv("__default") && (x=resolv("__default.all_constants")))    x=x();
pike.git/lib/master.pike.in:3351:    // Check for _static_modules.    mixed static_modules = _static_modules;    if (current_handler->get_default_module) {    mapping(string:mixed) default_module =    current_handler->get_default_module();    if (default_module) {    static_modules = default_module["_static_modules"] || ([]);    }    }    -  node = joinnode(({ instantiate_static_modules(static_modules), +  node = joinnode(({ +  // Kluge to get _static_modules to work at top level. +  ([ "_static_modules" : static_modules ]), +  instantiate_static_modules(static_modules),    // Copy relevant stuff from the root module.    @filter(root_module->joined_modules, -  lambda(mixed x) { -  return objectp(x) && x->is_resolv_dirnode; -  }) }), +  is_dirnode) +  }),    current_handler,    root_module->fallback_module,    "predef::");    -  // FIXME: Is this needed? -  // Kluge to get _static_modules to work at top level. -  node->cache->_static_modules = static_modules; -  +     return node;    }    -  //! +  //! Look up @[identifier] in the root module.    mixed resolv_base(string identifier, string|void current_file, -  object|void current_handler) +  object|void current_handler, +  object|void current_compat_handler)    {    // werror("Resolv_base(%O)\n",identifier);    return get_root_module(current_handler)[identifier];    }       //! Same as @[resolv], but throws an error instead of returning    //! @[UNDEFINED] if the resolv failed.    mixed resolv_or_error(string identifier, string|void current_file,    void|object current_handler)    {    mixed res = resolv(identifier, current_file, current_handler); -  if(zero_type(res)) error("Could not resolve %s.\n", identifier); +  if(undefinedp(res)) error("Could not resolve %s.\n", identifier);    return res;    }    -  +  //! Resolve the @[identifier] expression.    //! -  +  //! @returns +  //! Returns the value of the @[identifier] if it exists, +  //! and @[UNDEFINED] otherwise.    mixed resolv(string identifier, string|void current_file, -  object|void current_handler) +  object|void current_handler, +  object|void current_compat_handler)    {    resolv_debug("resolv(%O, %O)\n",identifier, current_file);    INC_RESOLV_MSG_DEPTH();       // FIXME: Support having the cache in the handler?    if( no_resolv[ identifier ] ) {    DEC_RESOLV_MSG_DEPTH();    resolv_debug("resolv(%O, %O) => excluded\n",identifier, current_file);    return UNDEFINED;    }       if (current_file && !stringp(current_file)) { -  error("resolv(%O, %O, %O): current_file is not a string!\n", -  identifier, current_file, current_handler); +  error("resolv(%O, %O, %O, %O): current_file is not a string!\n", +  identifier, current_file, current_handler, current_compat_handler);    }       array(string) tmp = identifier/"::";    mixed ret;    if (sizeof(tmp) > 1) {    string scope = tmp[0];    tmp = tmp[1]/".";    switch(scope) {    case "predef":    ret = all_constants();    break;    default:    if (sscanf(scope, "%d.%d%*s", int major, int minor) == 3) {    // Versioned identifier.    ret = get_compilation_handler(major, minor);    if (ret) {    mixed mod = ret->get_default_module(); -  if (!zero_type(mod = mod[tmp[0]])) { +  if (mod && !undefinedp(mod = mod[tmp[0]])) {    ret = mod;    } else {    ret = ret->resolv(tmp[0]);    }    tmp = tmp[1..];    break;    }    }    error("resolv(%O, %O, %O): Unsupported scope: %O!\n",    identifier, current_file, current_handler, scope);    }    } else {    tmp = identifier/"."; -  ret = resolv_base(tmp[0], current_file, current_handler); +  ret = resolv_base(tmp[0], current_file, +  current_handler, current_compat_handler);    tmp = tmp[1..];    }    foreach(tmp,string index) {    resolv_debug("indexing %O with %O...\n",    ret, index); -  resolv_debug("indices(%O): %O\n", ret, indices(ret)); -  if (zero_type(ret)) break; +  // NB: Running indices() on directory nodes will force them to load +  // all their content, which is probably NOT what you want... +  // resolv_debug("indices(%O): %O\n", ret, indices(ret)); +  if (undefinedp(ret)) break;    ret = ret[index];    }    DEC_RESOLV_MSG_DEPTH();   #ifdef RESOLV_DEBUG -  if (zero_type (ret)) +  if (undefinedp (ret))    resolv_debug("resolv(%O, %O) => not found\n",identifier, current_file);    else    resolv_debug("resolv(%O, %O) => found %O\n",identifier, current_file, ret);   #endif /* RESOLV_DEBUG */    return ret;    }          //! This function is called whenever an #include directive is    //! encountered. It receives the argument for #include and should -  //! return the file name of the file to include +  //! return the file name of the file to include. +  //! +  //! @seealso +  //! @[read_include()]    string handle_include(string f,    string current_file,    int local_include)    {    if(local_include)    {    if(IS_ABSOLUTE_PATH(f)) return combine_path(f);    return combine_path_with_cwd(dirname(current_file), f);    }    else
pike.git/lib/master.pike.in:3484:    }    if (fallback_resolver) {    return fallback_resolver->handle_include(f, current_file,    local_include);    }    }    // Failed.    return 0;    }    +  //! Read the file specified by @[handle_include()].    //! -  +  //! @seealso +  //! @[handle_include()]    string read_include(string f)    {    AUTORELOAD_CHECK_FILE(f);    if (array|object err = catch {    return master_read_file (f);    })    compile_cb_rethrow (err);    }       protected string _sprintf(int t)    {    return t=='O' && sprintf("CompatResolver(%O)",ver);    }   }      inherit CompatResolver;    -  + //! @namespace predef:: +  + //! @class __dirnode +  + //! @decl inherit MasterObject.dirnode +  + //! @endclass +  + //! @class __joinnode +  + //! @decl inherit MasterObject.joinnode +  + //! @endclass +  + //! @decl void add_include_path(string tmp) + //! Add a directory to search for include files.   //! - class Pike06Resolver - { -  inherit CompatResolver; + //! This is the same as the command line option @tt{-I@}. + //! + //! @note + //! Note that the added directory will only be searched when using + //! < > to quote the included file. + //! + //! @seealso + //! @[remove_include_path()] + //!    -  //! In Pike 0.6 the current directory was implicitly searched. -  mixed resolv_base(string identifier, string|void current_file, -  object|void current_handler) -  { -  if (current_file) { -  joinnode node = handle_import(".", current_file, current_handler); -  return node[identifier] || -  ::resolv_base(identifier, current_file, current_handler); -  } -  return ::resolv_base(identifier, current_file, current_handler); -  } - } + //! @decl void remove_include_path(string tmp) + //! Remove a directory to search for include files. + //! + //! This function performs the reverse operation of @[add_include_path()]. + //! + //! @seealso + //! @[add_include_path()] + //!    -  + //! @decl void add_module_path(string path, string|void subpath) + //! Add a directory to search for modules. + //! + //! This is the same as the command line option @tt{-M@}. + //! + //! @seealso + //! @[remove_module_path()] + //! + //! @param path + //! a string containing a path to search for Pike modules. May be a + //! directory, or a path to a ZIP archive. If a ZIP archive path is + //! provided, modules will be loaded from a directory, "modules" within + //! the ZIP archive (see the subpath argument). + //! + //! @param subpath + //! if path is a ZIP archive, this argument will determine the path within + //! the archive to be searched. + //! +  + //! @decl void remove_module_path(string tmp) + //! Remove a directory to search for modules. + //! + //! This function performs the reverse operation of @[add_module_path()]. + //! + //! @seealso + //! @[add_module_path()] + //! +  + //! @decl void add_program_path(string tmp) + //! Add a directory to search for programs. + //! + //! This is the same as the command line option @tt{-P@}. + //! + //! @seealso + //! @[remove_program_path()] + //! +  + //! @decl void remove_program_path(string tmp) + //! Remove a directory to search for programs. + //! + //! This function performs the reverse operation of @[add_program_path()]. + //! + //! @seealso + //! @[add_program_path()] + //! +  + //! @endnamespace +    //! These are useful if you want to start other Pike processes   //! with the same options as this one was started with.   string _pike_file_name;   string _master_file_name;      // Gets set to 1 if we're in async-mode (script->main() returned <0)   private int(0..1) _async=0;      //! Returns 1 if we´re in async-mode, e.g. if the main method has   //! returned a negative number.
pike.git/lib/master.pike.in:3690:    no_resolv[ feature ] = 1;    break;    }    }    break;       case "debug":    debug+=(int)q[i][1];    break;    - #if constant(_compiler_trace) -  case "compiler_trace": -  _compiler_trace(1); -  break; - #endif /* constant(_compiler_trace) */ -  - #if constant(_assembler_debug) -  case "assembler_debug": -  _assembler_debug((int)q[i][1]); -  break; - #endif /* constant(_assembler_debug) */ -  - #if constant(_optimizer_debug) -  case "optimizer_debug": -  _optimizer_debug((int)q[i][1]); -  break; - #endif /* constant(_optimizer_debug) */ -  +     case "trace":    trace+=(int)q[i][1];    break;       case "modpath":    add_module_path(q[i][1]);    break;       case "ipath":    add_include_path(q[i][1]);
pike.git/lib/master.pike.in:3747:    run_tool = 1;    break;       case "show_cpp_warn":    show_if_constant_errors = 1;    break;    }    }       cur_compat_ver = Version (compat_major, compat_minor); +  if (cur_compat_ver < lowestcompat) +  { +  werror("This Pike only supports compatibility down to %s.\n", +  (string)lowestcompat); +  cur_compat_ver = lowestcompat; +  compat_major = lowestcompat->major; +  compat_minor = lowestcompat->minor; +  }    if (compat_major != -1) {    object compat_master = get_compat_master (compat_major, compat_minor); -  -  if (cur_compat_ver <= Version (7, 6)) { -  mapping(string:array(string)) compat_env = ([]); -  foreach (Builtin._getenv(); string var; string val) { - #ifdef __NT__ -  compat_env[lower_case (var)] = ({var, val}); - #else -  compat_env[var] = ({var, val}); - #endif +     } -  compat_master->environment = compat_env; -  } -  } +        foreach(q, array opts)    {    switch(opts[0])    {    case "dumpversion":    write("%d.%d.%d\n", __REAL_MAJOR__, __REAL_MINOR__, __REAL_BUILD__);    exit(0);       case "version": -  exit(0, string_to_utf8(version() + " Copyright © 1994-2013 Linköping University\n" +  exit(0, string_to_utf8(version() + " Copyright © 1994-2018 Linköping University\n"    "Pike comes with ABSOLUTELY NO WARRANTY; This is free software and you are\n"    "welcome to redistribute it under certain conditions; read the files\n"    "COPYING and COPYRIGHT in the Pike distribution for more details.\n"));       case "help":    exit( 0, main_resolv("Tools.MasterHelp")->do_help(opts[1]) );       case "features":    postparseaction="features";    break;
pike.git/lib/master.pike.in:3819:    default:    exit(1, "Unknown path type %s\n", opts[1]);    }    exit(0);    }       exit(0, format_paths());       case "execute":    main_resolv( "Gmp.bignum" ); -  random_seed((time() ^ (getpid()<<8))); +     argv = tmp->get_args(argv,1);       program prog;    mixed compile_err = catch {; -  if(cur_compat_ver <= Version(7,4)) -  prog = compile_string( -  "mixed create(int argc, array(string) argv,array(string) env){"+ -  opts[1]+";}"); -  else if (intp (opts[1])) +  if (intp (opts[1]))    prog = compile_string ("mixed run() {}");    else {    string code = opts[1];    while(sscanf(code, "%sCHAR(%1s)%s", code, string c, string rest)==3)    code += c[0] + rest; -  if (cur_compat_ver <= Version (7, 6)) +     prog = compile_string(    "#define NOT(X) !(X)\n" -  "mixed run(int argc, array(string) argv," -  "mapping(string:string) env){"+ -  code+";}"); -  else -  prog = compile_string( -  "#define NOT(X) !(X)\n" +     "mixed run(int argc, array(string) argv){" + code + ";}");    }    };       if (compile_err) {    if (compile_err->is_cpp_or_compilation_error) {    // Don't clutter the output with the backtrace for    // compilation errors.    exit (20, call_describe_error (compile_err));    }
pike.git/lib/master.pike.in:3866:   #if constant(_debug)    if(debug) _debug(debug);   #endif    if(trace) trace = predef::trace(trace);    mixed ret;    mixed err = catch {    // One reason for this catch is to get a new call to    // eval_instruction in interpret.c so that the debug and    // trace levels set above take effect in the bytecode    // evaluator. -  if(cur_compat_ver <= Version(7,4)) -  prog (sizeof(argv),argv,getenv()); -  else if (cur_compat_ver <= Version (7, 6)) -  ret = prog()->run(sizeof(argv),argv,getenv()); -  else +     ret = prog()->run(sizeof(argv),argv);    };    predef::trace(trace);    if (err) {    handle_error (err);    ret = 10;    }    if(stringp(ret)) {    write(ret);    if(ret[-1]!='\n') write("\n");    }    if(!intp(ret) || ret<0) ret=0;    exit(ret);       case "preprocess":    main_resolv( "Gmp.bignum" );    write(cpp(master_read_file(opts[1]),opts[1]));    exit(0); -  +  +  case "compiler_trace": +  function(int:void) compiler_trace = +  main_resolv("Debug.compiler_trace"); +  if (compiler_trace) { +  compiler_trace(1);    } -  +  break; +  +  case "assembler_debug": +  function(int:void) assembler_debug = +  main_resolv("Debug.assembler_debug"); +  if (assembler_debug) { +  assembler_debug((int)opts[1]);    } -  +  break;    -  +  case "optimizer_debug": +  function(int:void) optimizer_debug = +  main_resolv("Debug.optimizer_debug"); +  if (optimizer_debug) { +  optimizer_debug((int)opts[1]); +  } +  break; +  } +  } +     argv = tmp->get_args(argv,1);    }    else    cur_compat_ver = Version (compat_major, compat_minor);       switch (postparseaction)    {    case "features":    write( main_resolv( "Tools.Install.features" )()*"\n"+"\n" );    exit(0);
pike.git/lib/master.pike.in:3917:    "\n"    "pike binary..."+_pike_file_name+"\n"+    format_paths() + "\n"    "Features......"+    main_resolv( "Tools.Install.features" )()*"\n "+    "\n");    exit(0);    }       main_resolv( "Gmp.bignum" ); -  random_seed(time() ^ (getpid()<<8)); +        if(sizeof(argv)==1)    {    if(run_tool) {    werror("Pike -x specificed without tool name.\n"    "Available tools:\n");    mapping t = ([]);    int i;    object ts = main_resolv("Tools.Standalone",    get_compilation_handler(compat_major,
pike.git/lib/master.pike.in:3983:    if( !file_stat(fn) )    {    if( file_stat(fn+".pike") )    fn += ".pike";    else    exit(1, "Could not find file %O.\n", fn);    }    if( !file_stat(fn)->isreg )    exit(1, "File %O is not a regular file.\n", fn);    if( !master_read_file(fn) ) -  exit(1, "File %O is not readable. %s.\n", -  fn, strerror(errno())); +  exit(1, "File %O is not readable. %s.\n", fn, strerror(errno()));    if (objectp (err) && err->is_cpp_or_compilation_error)    exit(1, "Pike: Failed to compile script.\n");    else    exit(1, "Pike: Failed to compile script:\n"    "%s", call_describe_backtrace(err));    }       // Don't list the program with its real path in the programs    // mapping, so that reverse lookups (typically by the codec)    // always find the canonical "/main" instead.
pike.git/lib/master.pike.in:4016:   #endif    if(trace) trace = predef::trace(trace);    mixed ret;    mixed err = catch {    // The main reason for this catch is actually to get a new call    // to eval_instruction in interpret.c so that the debug and    // trace levels set above take effect in the bytecode evaluator.    // Note that it won't work if there's another catch surrounding    // this one.    object script; -  if(cur_compat_ver <= Version(7,4)) { -  script=prog(); -  } -  else { +     script=prog(argv); -  } +     if(!script->main)    error("Error: %s has no main().\n", argv[0]); -  if (cur_compat_ver <= Version (7, 6)) -  ret=script->main(sizeof(argv),argv,getenv()); -  else if (cur_compat_ver <= Version (8, 0)) +  if (cur_compat_ver <= Version (8, 0))    ret = script->main(sizeof(argv),argv);    else    {    mixed first_arg = __get_first_arg_type(_typeof(script->main));    // NB: first_arg may be zero eg in case main() ignores all args.    if( first_arg && (typeof(argv) <= first_arg) ) {    // argv accepted as first argument.    ret=script->main(argv);    } else    ret=script->main(sizeof(argv),argv);
pike.git/lib/master.pike.in:4243:   //! Called for every runtime warning. The first argument identifies   //! where the warning comes from, the second identifies the specific   //! message, and the rest depends on that. See code below for currently   //! implemented warnings.   void runtime_warning (string where, string what, mixed... args)   {    if (want_warnings)    switch (where + "." + what) {    case "gc.bad_cycle":    // args[0] is an array containing the objects in the cycle -  // which aren't destructed and have destroy() functions. +  // which aren't destructed and have _destruct() functions.   #if 0    // Ignore this warning for now since we do not yet have a weak    // modifier, so it can't be avoided in a reasonable way. -  werror ("GC warning: Garbing cycle where destroy() will be called " +  werror ("GC warning: Garbing cycle where _destruct() will be called "    "in arbitrary order:\n%{ %s\n%}",    sprintf("%O", args[0][*]));   #endif    break;       default:    werror ("%s warning: %s %O\n", capitalize (where), what, args);    }   }   
pike.git/lib/master.pike.in:4280:       if (mixed err = catch {    object decoder = ([function(string:object)]Charset.decoder)(charset);    return ([function(void:string)]([function(string:object)]decoder->    feed)(data)->drain)();    })    compile_cb_rethrow (err);   }       + //! Class used by @[describe_backtrace()] to describe values in backtraces.   class Describer   {    int clipped=0;    int canclip=0;    mapping(mixed:int|string) ident = ([]);    int identcount = 0;       void identify_parts (mixed stuff)    {    // Use an array as stack here instead of recursing directly; we
pike.git/lib/master.pike.in:4325:    {    canclip++;    if(sizeof(m) < maxlen)    {    string t = sprintf("%q", m);    if (sizeof(t) < (maxlen + 2))    return t;    t = 0;    }    clipped++; -  if(maxlen>10) -  return sprintf("%q+[%d]",m[..maxlen-5],sizeof(m)-(maxlen-5)); +  if(maxlen>10) { +  int h = (3*maxlen)/4; +  return sprintf("%q+[%d]+%q", +  m[..h-5], +  sizeof(m)-(maxlen-8), +  m[sizeof(m) - (maxlen - (h + 4))..]); +  }       return "string["+sizeof(m)+"]";    }       string describe_array (array m, int maxlen)    {    if(!sizeof(m)) return "({})";    else {    if(maxlen<5)    {
pike.git/lib/master.pike.in:4373:    else if (intp (ident[m]) && ident[m] > 1)    ident[m] = "@" + identcount++;    };       string res;    if (catch (res=sprintf("%t",m)))    res = "object"; // Object with a broken _sprintf(), probably.    switch(res)    {    case "int": -  if (!m && zero_type (m) == 1) +  if (!m && undefinedp (m) == 1)    return "UNDEFINED";    case "float":    return (string)m;    case "string":    return describe_string ([string]m, maxlen);    case "array":    res = describe_array ([array]m, maxlen);    break;    case "mapping":    res = describe_mapping ([mapping]m, maxlen);
pike.git/lib/master.pike.in:4664:    return res + ind[i] + ".";    }    }    };    }       // We're really out of luck here...    return res + (describe_program(parent_fun)||"unknown_program") + "()->";   }    - //! + //! Function called by @expr{sprintf("%O")@} for objects that don't + //! have an @[lfun::_sprintf()], or have one that returns @expr{UNDEFINED@}.   string describe_object(object o)   {    string s; -  if(zero_type (o)) return 0; // Destructed. +  if(undefinedp (o)) return 0; // Destructed.       // Handled by the search of all_constants() below.    // if (o == _static_modules) return "_static_modules";       program|function(mixed...:void|object) parent_fun = object_program(o);       /* Constant object? */    catch {    object|program parent_obj =    (function_object(parent_fun) || function_program(parent_fun));
pike.git/lib/master.pike.in:4707:    if ((s = programs_reverse_lookup (parent_fun)) &&    (s=program_path_to_name(s, "", "", "()")))    return s;    /* Try identifying the program. */    if(( s=describe_program(parent_fun) ))    return s+"()";       return 0;   }    - //! + //! Function called by @expr{sprintf("%O")@} for programs.   string describe_program(program|function p)   {    string s;    if(!p) return 0;       if (p == object_program (_static_modules))    return "object_program(_static_modules)";       if(programp(p) &&    (s = programs_reverse_lookup ([program] p)) &&
pike.git/lib/master.pike.in:4734:    return describe_module(tmp) + s;    }    }       if(s=Builtin.program_defined(p))    return BASENAME(s);       return search(all_constants(), p);   }    - //! + //! Function called by @[describe_backtrace()] to describe + //! functions in the backtrace.   string describe_function (function f)   {    if (!f) return 0;       string name;       if (name = search(all_constants(), f)) return name;       if(string s = programs_reverse_lookup (f))    {
pike.git/lib/master.pike.in:4773:    return s+"->"+name;    }    return name;   }      /* It is possible that this should be a real efun,    * it is currently used by handle_error to convert a backtrace to a    * readable message.    */    - //! @appears describe_backtrace + //! @namespace predef:: +    //! Return a readable message that describes where the backtrace   //! @[trace] was made (by @[backtrace]).   //!   //! It may also be an error object or array (typically caught by a   //! @[catch]), in which case the error message also is included in the   //! description.   //! -  + //! Pass @[linewidth] -1 to disable wrapping of the output. + //!   //! @seealso   //! @[backtrace()], @[describe_error()], @[catch()], @[throw()]   //!   string describe_backtrace(mixed trace, void|int linewidth)   {    int e;    string ret;    int backtrace_len=((int)getenv("PIKE_BACKTRACE_LEN")) || bt_max_string_len;       if(!linewidth)
pike.git/lib/master.pike.in:4808:    }       // Note: Partial code duplication in describe_error and get_backtrace.       if (objectp(trace) && ([object]trace)->is_generic_error) {    object err_obj = [object] trace;    if (mixed err = catch {       if (functionp (err_obj->message))    ret = err_obj->message(); -  else if (zero_type (ret = err_obj->error_message)) +  else if (undefinedp (ret = err_obj->error_message))    // For compatibility with error objects trying to behave    // like arrays.    ret = err_obj[0];    if (!ret)    ret = "";    else if (!stringp (ret))    ret = sprintf ("<Message in %O is %t, expected string>\n",    err_obj, ret);       if (functionp (err_obj->backtrace))    trace = err_obj->backtrace(); -  else if (zero_type (trace = err_obj->error_backtrace)) +  else if (undefinedp (trace = err_obj->error_backtrace))    // For compatibility with error objects trying to behave    // like arrays.    trace = err_obj[1];    if (!trace)    return ret + "<No backtrace>\n";    else if (!arrayp (trace))    return sprintf ("%s<Backtrace in %O is %t, expected array>\n",    ret, err_obj, trace);       })    return sprintf ("<Failed to index backtrace object %O: %s>\n", -  err_obj, trim_all_whites (call_describe_error (err))); +  err_obj, trim (call_describe_error (err)));    }       else if (arrayp(trace)) {    if (sizeof([array]trace)==2 && stringp(ret = ([array]trace)[0])) {    trace = ([array] trace)[1];    if(!trace)    return ret + "<No backtrace>\n";    else if (!arrayp (trace))    return sprintf ("%s<Backtrace in error array is %t, expected array>\n",    ret, trace);
pike.git/lib/master.pike.in:4937:    }    else if (stringp(tmp[2])) {    data = [string]tmp[2];    } else    data ="unknown function";       data+="("+    desc->describe_comma_list(tmp[3..], backtrace_len)+    ")";    -  if(sizeof(pos)+sizeof(data) < linewidth-4) +  if((linewidth == -1) || (sizeof(pos)+sizeof(data) < linewidth-4))    {    row=sprintf("%s: %s",pos,data);    }else{    row=sprintf("%s:\n%s",pos,sprintf(" %*-/s",linewidth-6,data));    }    } else {    row = pos;    }    }    else
pike.git/lib/master.pike.in:4961:    row = describe_program(object_program(tmp)) + " with broken _sprintf()";    } else {    row = "Destructed object";    }    }    }) {    row = sprintf("Error indexing backtrace line %d: %s (%O)!", e, err[0], err[1]);    }       int dup_frame; -  if (!zero_type(dup_frame = prev_pos[row])) { +  if (!undefinedp(dup_frame = prev_pos[row])) {    dup_frame -= sizeof(frames);    if (!loop_start) {    loop_start = dup_frame;    loop_next = dup_frame + 1;    loops = 0;    continue;    } else {    int new_loop = 0;    if (!loop_next) loop_next = loop_start, new_loop = 1;    if (dup_frame == loop_next++) {
pike.git/lib/master.pike.in:5012:    -loop_start, loops)});    frames += tail;    }       ret += frames * "";    }       return ret;   }    - //! @appears describe_error - //! +    //! Return the error message from an error object or array (typically   //! caught by a @[catch]). The type of the error is checked, hence   //! @[err] is declared as @expr{mixed@} and not @expr{object|array@}.   //!   //! If an error message couldn't be obtained, a fallback message   //! describing the failure is returned. No errors due to incorrectness   //! in @[err] are thrown.   //!   //! @seealso   //! @[describe_backtrace()], @[get_backtrace]
pike.git/lib/master.pike.in:5037:    mixed msg;       // Note: Partial code duplication in describe_backtrace and get_backtrace.       if (objectp(err) && ([object]err)->is_generic_error) {    object err_obj = [object] err;    if (mixed err = catch {       if (functionp (err_obj->message))    msg = err_obj->message(); -  else if (zero_type (msg = err_obj->error_message)) +  else if (undefinedp (msg = err_obj->error_message))    // For compatibility with error objects trying to behave    // like arrays.    msg = err_obj[0];       if (stringp (msg))    return msg;    else if (!msg)    return "<No error message>\n";    else    return sprintf ("<Message in %O is %t, expected string>\n",    err_obj, msg);       })    return sprintf ("<Failed to index error object %O: %s>\n", -  err_obj, trim_all_whites (call_describe_error (err))); +  err_obj, trim (call_describe_error (err)));    }       else if (arrayp(err) && sizeof([array]err)==2 &&    (!(msg = ([array]err)[0]) || stringp (msg)))    return [string] msg || "<No error message>\n";       else    return sprintf ("<Invalid error container: %O>\n", err);   }    - //! @appears get_backtrace - //! +    //! Return the backtrace array from an error object or array   //! (typically caught by a @[catch]), or zero if there is none. Errors   //! are thrown on if there are problems retrieving the backtrace.   //!   //! @seealso   //! @[describe_backtrace()], @[describe_error()]   //!   array get_backtrace (object|array err)   {    array bt;       // Note: Partial code duplication in describe_backtrace and describe_error.       if (objectp(err) && ([object]err)->is_generic_error) {    object err_obj = [object] err;       if (functionp (err_obj->backtrace))    bt = err_obj->backtrace(); -  else if (zero_type (bt = err_obj->error_backtrace)) +  else if (undefinedp (bt = err_obj->error_backtrace))    // For compatibility with error objects trying to behave like    // arrays.    bt = err_obj[1];       if (bt && !arrayp (bt))    error ("Backtrace in %O is %t, expected array.\n", err_obj, bt);    }       else if (arrayp(err) && sizeof([array]err)==2 &&    (!(bt = ([array]err)[1]) || arrayp (bt)))    {}       else if (err)    error ("Invalid error container: %O\n", err);       return bt;   }    -  + //! @endnamespace    -  + void thread_quanta_exceeded(object thread, int ns) + { +  werror("Thread quanta exceeded for %O (%d ns):\n" +  "%s\n", +  thread, ns, +  describe_backtrace(thread->backtrace())); + } +  +    #ifdef ENCODE_DEBUG   # define ENC_MSG(X...) do werror (X); while (0)   # define ENC_RETURN(val) do { \    mixed _v__ = (val); \    werror (" returned %s\n", \ -  zero_type (_v__) ? "UNDEFINED" : \ +  undefinedp (_v__) ? "UNDEFINED" : \    narrowify_string(sprintf ("%O", _v__))); \    return _v__; \   } while (0)   #else   # define ENC_MSG(X...) do {} while (0)   # define ENC_RETURN(val) do return (val); while (0)   #endif      #ifdef DECODE_DEBUG   # define DEC_MSG(X...) do werror (X); while (0)   # define DEC_RETURN(val) do { \    mixed _v__ = (val); \    werror (" returned %s\n", \ -  zero_type (_v__) ? "UNDEFINED" : \ +  undefinedp (_v__) ? "UNDEFINED" : \    narrowify_string(sprintf ("%O", _v__))); \    return _v__; \   } while (0)   #else   # define DEC_MSG(X...) do {} while (0)   # define DEC_RETURN(val) do return (val); while (0)   #endif      class Encoder   //! @appears Pike.Encoder
pike.git/lib/master.pike.in:5239:    return "r" + name;    }       if (objectp (resolved)) {    if (object_program (resolved) == what) {    ENC_MSG (" compare_resolved: %O is program of %O\n", what, resolved);    append = ({'p'});    break compare;    }    -  if ((resolved->is_resolv_joinnode) && +  if (is_joinnode(resolved) &&    (sizeof(resolved->joined_modules) == 1)) {    ENC_MSG(" compare_resolved: %O is a single element joinnode.\n",    resolved);    resolved = resolved->joined_modules[0];    } -  if (resolved->is_resolv_dirnode) { +  if (is_dirnode(resolved)) {    if (resolved->module == what) {    ENC_MSG (" compare_resolved: %O is dirnode module of %O\n", what, resolved);    append = ({'m'});    resolved = resolved->module;    break compare;    }    else if (object_program (resolved->module) == what) {    ENC_MSG (" compare_resolved: %O is program of dirnode module of %O\n",    what, resolved);    append = ({'m', 'p'});    break compare;    }    else    ENC_MSG (" compare_resolved: %O is different from dirnode module %O\n",    what, resolved->module);    }   #if 0    // This is only safe if the joinnode modules don't conflict,    // and we don't know that. -  if (resolved->is_resolv_joinnode) { +  if (is_joinnode(resolved)) {    ENC_MSG (" compare_resolved: searching for %O in joinnode %O\n",    what, resolved);    foreach (resolved->joined_modules, mixed part)    if (string|array name = compare_resolved (name, what, part,    module_object)) {    if (module_object) module_object[0] = resolved;    return name;    }    }   #endif
pike.git/lib/master.pike.in:5319:    if (what == encoded) {    ENC_MSG (" got the thing to encode - encoding recursively\n");    return UNDEFINED;    }       if (string id = rev_constants[what]) ENC_RETURN (id);    if (string id = rev_static_modules[what]) ENC_RETURN (id);       if (objectp (what)) {    -  if (what->is_resolv_dirnode) { +  if (is_dirnode(what)) {    ENC_MSG (" is a dirnode\n");    string name = program_path_to_name (what->dirname);    if (string|array ref = compare_resolved (name, what, resolv (name),    module_object))    ENC_RETURN (ref);    }    -  else if (what->is_resolv_joinnode) { +  else if (is_joinnode(what)) {    ENC_MSG (" is a joinnode\n");    object modules = Builtin.array_iterator (what->joined_modules);    object|mapping value;    check_dirnode: -  if (modules && objectp (value = modules->value()) && -  value->is_resolv_dirnode) { +  if (modules && (value = modules->value()) && is_dirnode(value)) {    string name = program_path_to_name (value->dirname);    modules += 1;    foreach (modules;; value) -  if (!objectp (value) || !value->is_resolv_dirnode || +  if (!is_dirnode(value) ||    program_path_to_name (value->dirname) != name)    break check_dirnode;    ENC_MSG (" joinnode has consistent name %O\n", name);    if (string|array ref = compare_resolved (name, what, resolv (name),    module_object))    ENC_RETURN (ref);    }    }       else if (what->is_pike_master) {
pike.git/lib/master.pike.in:5542:    // return ({});    }    DEC_RETURN (([function]x->_encode)());    }       protected void create (void|mixed encoded)    //! Creates an encoder instance. If @[encoded] is specified, it's    //! encoded instead of being reverse resolved to a name. That's    //! necessary to encode programs.    { -  this_program::encoded = encoded; +  this::encoded = encoded;       foreach (all_constants(); string var; mixed val)    rev_constants[val] = "c" + var;       // FIXME: We don't have any good way to do reverse lookups on    // things that are assigned to module variables. Here we use    // rev_constants only to find the most vital ones.    {    object val_module = resolv ("Val");    foreach (indices (val_module), string var) {
pike.git/lib/master.pike.in:5594:   //! @appears Pike.Decoder   //!   //! Codec for use with @[decode_value]. This is the decoder   //! corresponding to @[Encoder]. See that one for more details.   {    protected int unregistered = 1;       object __register_new_program(program p)    {    DEC_MSG ("__register_new_program (%O)\n", p); +  // NB: decode_value() has already locked the compiler, so we +  // should not need to lock it here.    if(unregistered && fname)    {    unregistered = 0;    resolv_debug("register %s\n", fname);    programs[fname]=p;    if (mkobj)    DEC_RETURN (objectp (objects[p]) ? objects[p] : (objects[p]=__null_program()));    }    DEC_RETURN (0);    }       protected mixed thingof (string|array what)    {    mixed res;    array sublist;    if (arrayp (what)) sublist = [array]what, what = [array|string]sublist[0];       switch (what[0]) {    case 'c': -  if (zero_type (res = all_constants()[what[1..]])) +  if (undefinedp (res = all_constants()[what[1..]]))    error ("Cannot find global constant %O.\n", what[1..]);    break;    case 's': -  if (zero_type (res = _static_modules[what[1..]])) +  if (undefinedp (res = _static_modules[what[1..]]))    error ("Cannot find %O in _static_modules.\n", what[1..]);    break;    case 'r': -  if (zero_type (res = resolv ([string]what[1..], fname, handler))) +  if (undefinedp (res = resolv ([string]what[1..], fname, handler)))    error ("Cannot resolve %O.\n", what[1..]);    break;    case 'p':    if (!(res = low_cast_to_program ([string]what[1..], fname, handler)))    error ("Cannot find program for %O.\n", what[1..]);    break;    case 'o':    if (!objectp(res = low_cast_to_object([string]what[1..], fname, handler)))    error ("Cannot find object for %O.\n", what[1..]);    break;
pike.git/lib/master.pike.in:5648:    DEC_MSG (" got %O\n", res);       if (sublist) {    mixed subres = res;    for (int i = 1; i < sizeof (sublist); i++) {    mixed op = sublist[i];    if (stringp (op)) {    if (!programp (subres) && !objectp (subres) && !mappingp (subres))    error ("Cannot subindex %O%{[%O]%} since it's a %t.\n",    res, sublist[1..i-1], subres); -  if (zero_type (subres = ([mapping]subres)[op])) +  if (undefinedp (subres = ([mapping]subres)[op]))    error ("Cannot find %O in %O%{[%O]%}.\n",    op, res, sublist[1..i-1]);    DEC_MSG (" indexed with %O: %O\n", op, subres);    }    else switch (op) {    case 'm': -  if (objectp (subres) && ([object]subres)->is_resolv_joinnode) { +  if (is_joinnode(subres)) {    dirnode found;    foreach (([object(joinnode)]subres)->joined_modules,    object|mapping part) -  if (objectp (part) && part->is_resolv_dirnode && part->module) { +  if (is_dirnode(part) && part->module) {    if (found)    error ("There are ambiguous module objects in %O.\n",    subres);    else    found = [object(dirnode)]part;    }    if (found) subres = found;    }    -  if (objectp (subres) && ([object]subres)->is_resolv_dirnode) { +  if (is_dirnode(subres)) {    if (([object]subres)->module) {    subres = ([object]subres)->module;    DEC_MSG (" got dirnode module %O\n", subres);    }    else    error ("Cannot find module object in dirnode %O.\n", subres);    }    else    error ("Cannot get module object in thing that isn't "    "a dirnode or unambiguous joinnode: %O\n", subres);
pike.git/lib/master.pike.in:5700:    }    res = subres;    }       return res;    }       object objectof (string|array what)    {    DEC_MSG ("objectof (%O)\n", what); -  if (!what) { -  // This is necessary for compatibility with 7.2 encoded values: -  // If an object was fed to encode_value there and there was no -  // codec then a zero would be encoded silently since the failed -  // call to nameof was ignored. decode_value would likewise -  // silently ignore the failed call objectof(0) and a zero would -  // be decoded. Now we supply a fairly capable codec which is -  // used by default and we therefore get these objectof(0) calls -  // here. So if we throw an error we can't decode values which -  // 7.2 would encode and decode without a codec (albeit partly -  // incorrectly). So just print a sulky warning and continue.. :P -  DEC_MSG ("Warning: Decoded broken object identifier to zero.\n"); -  DEC_RETURN (0); -  } +  if (!what) +  error ("Decoded broken object identifier to zero.\n");    DEC_RETURN ([object] thingof (what));    }       function functionof (string|array what)    {    DEC_MSG ("functionof (%O)\n", what);    DEC_RETURN ([function] thingof (what));    }       program programof (string|array what)
pike.git/lib/master.pike.in:5842:    //! Methods define so that version objects    //! can be compared and ordered.    protected int `<(mixed v) { return objectp(v) && CMP(v) < 0; }    protected int `>(mixed v) { return objectp(v) && CMP(v) > 0; }    protected int `==(mixed v) { return objectp(v) && CMP(v)== 0; }    protected int __hash() { return major * 4711 + minor ; }       protected string _sprintf(int t) {    switch(t) {    case 's': return sprintf("%d.%d",major,minor); -  case 'O': return sprintf("%O(%s)", this_program, this); +  case 'O': return sprintf("%O(%s)", this_program, _sprintf('s'));    }    }       //! The version object can be casted into a string.    protected mixed cast(string type)    { -  switch(type) -  { -  case "string": +  if( type=="string" )    return sprintf("%d.%d",major,minor); -  +  return UNDEFINED;    }   } - } +       //! Version information about the current Pike version.   Version currentversion = Version(__REAL_MAJOR__, __REAL_MINOR__);    -  + Version lowestcompat = Version(Builtin.LOWEST_COMPAT_MAJOR, +  Builtin.LOWEST_COMPAT_MINOR); +    mapping(Version:CompatResolver) compat_handler_cache = ([    currentversion:this_object(),   ]);      CompatResolver get_compilation_handler(int major, int minor)   {    Version v=Version(major,minor);       if(v > currentversion)    {    /* Do we want to make an error if major.minor > __MAJOR__.__MINOR ?    *    * No; it's useful for referring to the next version when writing    * compat modules.    */    return 0;    }       CompatResolver ret;    -  if(!zero_type(ret=compat_handler_cache[v])) return ret; +  if(!undefinedp(ret=compat_handler_cache[v])) return ret;       array(string) files;    array(Version) available=({});      #if "#share_prefix#"[0]!='#'    if (!(files = master_get_dir("#share_prefix#"))) { -  werror ("Error listing directory %O: %s\n", -  "#share_prefix#", strerror (errno())); +  werror ("Error listing directory %O: %s.\n", +  "#share_prefix#", strerror(errno()));    files = ({});    }    foreach(files, string ver)    {    if(sscanf(ver,"%d.%d",int maj, int min))    {    Version x=Version(maj, min) ;    if(x >= v)    available|=({ x });    }    }   #endif      #if "#lib_prefix#"[0]!='#'    if (!(files = master_get_dir("#lib_prefix#"))) { -  werror ("Error listing directory %O: %s\n", -  "#lib_prefix#", strerror (errno())); +  werror ("Error listing directory %O: %s.\n", +  "#lib_prefix#", strerror(errno()));    files = ({});    }    foreach(files, string ver)    {    if(sscanf(ver,"%d.%d",int maj, int min))    {    Version x=Version(maj, min) ;    if(x >= v)    available|=({ x });    }
pike.git/lib/master.pike.in:5949:       // The root resolver is this object.    ret = this;       foreach(reverse(available), Version tmp)    {    CompatResolver compat_handler = compat_handler_cache[tmp];    if (!compat_handler) {    // Create a new compat handler, that    // falls back to the successor version. -  if (tmp <= Version(0, 6)) { -  compat_handler = Pike06Resolver(tmp, ret); -  } else { +     compat_handler = CompatResolver(tmp, ret); -  } +        string base;   #if "#lib_prefix#"[0]!='#'    base=combine_path("#lib_prefix#",sprintf("%s",tmp));    compat_handler->add_module_path(combine_path(base,"modules"));    compat_handler->add_include_path(combine_path(base,"include"));   #endif      #if "#share_prefix#"[0]!='#'    base=combine_path("#share_prefix#",sprintf("%s",tmp));
pike.git/lib/master.pike.in:5994:    }       // Note: May duplicate the assignment above.    compat_handler_cache[v] = ret;       return ret;   }      string _sprintf(int t)   { -  // NOTE: The ||'O' is for Pike 7.2 compat only. -  switch(t||'O') { +  switch(t) {    // FIXME: What good is this lying for 't'? The master is still an    // object.. /mast    case 't': return "master";    case 'O': return "master()";    }   }      //! Return a master object compatible with the specified version of Pike.   //!   //! This function is used to implement the various compatibility versions   //! of @[master()].   //!   //! @seealso   //! @[get_compilation_handler()], @[master()]   object get_compat_master(int major, int minor)   { -  if ((major < 7) || ((major == 7) && (minor < 9))) -  return Pike_7_8_master::get_compat_master(major, minor); -  // 7.9 and later. +  if ((major < 8) || ((major == 8) && (minor < 1))) +  return Pike_8_0_master::get_compat_master(major, minor); +  // 8.1 and later.    return this;   }