pike.git / lib / master.pike.in

version» Context lines:

pike.git/lib/master.pike.in:49:   // 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 = ([]);
pike.git/lib/master.pike.in:423:      //! Namespaces for compat masters.   //!   //! This inherit is used to provide compatibility namespaces   //! for @[get_compat_master()].   //!   //! @seealso   //! @[get_compat_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:493:    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:638:      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,
pike.git/lib/master.pike.in:679:    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") )    {
pike.git/lib/master.pike.in:832:   //! @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))
pike.git/lib/master.pike.in:866:      #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:990:    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,
pike.git/lib/master.pike.in:1024:    }    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:1225:   {    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:1285:       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:1555:    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, '.') ?    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:1721:    };    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:1754:    "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    -  + //! @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 (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))   //
pike.git/lib/master.pike.in:1860:    // 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:2395:    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 (!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);    }    }
pike.git/lib/master.pike.in:2540:    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::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:2907:    {    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), -  Builtin.string_trim); -  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:2964:    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    */
pike.git/lib/master.pike.in:3021:    static_modules = default_module["_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::");       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(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();
pike.git/lib/master.pike.in:3097:    }    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);    // 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];
pike.git/lib/master.pike.in:3122:    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:3149:    }    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. + //! + //! 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()] + //! +  + //! @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:3397:       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-2017 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:3867:   //! 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:3904:       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:4293:    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(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);   
pike.git/lib/master.pike.in:4336:    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:4363:    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:4402:    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
pike.git/lib/master.pike.in:4643:    -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:4694:    }       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;
pike.git/lib/master.pike.in:4733:    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
pike.git/lib/master.pike.in:4878:    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:4958:    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:5296:    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 (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);