pike.git / lib / master.pike.in

version» Context lines:

pike.git/lib/master.pike.in:1:   // -*- Pike -*-   //   // 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.   // - // $Id: master.pike.in,v 1.309 2003/11/12 15:45:57 grubba Exp $ + // $Id: master.pike.in,v 1.310 2003/11/14 06:11:38 mast Exp $      #pike __REAL_VERSION__      // Some programs destroys character pairs beginning with the currency   // symbol when running in chinese locale.   #if "¤/" != "\244/"   #error "master.pike.in is corrupted."   #endif      // --- Some configurable parameters
pike.git/lib/master.pike.in:66:      //!   int compat_major=-1;      //!   int compat_minor=-1;         // --- Functions begin here.    - #define Stat _static_modules.___files.Stat + // Have to access some stuff without going through the resolver. + private constant Builtin = _static_modules.Builtin; + private constant Files = _static_modules.___files; +  + #define Stat Files.Stat   #define capitalize(X) (upper_case((X)[..0])+(X)[1..]) - #define write(X ...) _static_modules.___files()->_stdout->write(X) + #define write(X ...) (Files()->_stdout->write(X)) + #define trim_all_whites(X) (Builtin()->string_trim_all_whites (X))      #ifdef RESOLV_DEBUG      #if constant (thread_local)   static object resolv_msg_depth = thread_local();   // NOTE: May be used before __INIT has completed.   #define GET_RESOLV_MSG_DEPTH (resolv_msg_depth && resolv_msg_depth->get())   #define INC_RESOLV_MSG_DEPTH() (resolv_msg_depth && resolv_msg_depth->set (resolv_msg_depth->get() + 1))   #define DEC_RESOLV_MSG_DEPTH() (resolv_msg_depth && resolv_msg_depth->set (resolv_msg_depth->get() - 1))   #else
pike.git/lib/master.pike.in:299:    return compile(cpp(source, filename||"-", 1, handler,    compat_major, compat_minor),    handler,    compat_major,    compat_minor);   }      //!   string master_read_file(string file)   { -  object o=_static_modules.___files()->Fd(); +  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   static string current_path;   int cd(string s)   {    current_path=0;
pike.git/lib/master.pike.in:597:    fname = fakeroot (fname);    // FIXME: Not sure if this works correctly with the fakeroot and    // module relocation stuff.    foreach (pike_module_path, string path)    if (has_prefix (fname, path))    return map (pike_module_path, `+, "/", fname[sizeof (path)..], ".o");   #endif    return ({ fname + ".o" });   }    + static class CompileCallbackError (string error_message, array error_backtrace) + { +  constant is_generic_error = 1; +  constant is_compile_callback_error = 1; + } +  + static void compile_cb_error (string msg, mixed ... args) + // Use this to throw errors that should be converted to plain compile + // error messages, without backtraces being reported by + // compile_exception. + { +  if (sizeof (args)) msg = sprintf (msg, @args); +  array bt = backtrace(); +  bt = bt[..sizeof (bt) - 2]; +  throw (CompileCallbackError (msg, bt)); + } +  + static void compile_cb_rethrow (object|array err) + // Use this to rethrow errors that should be converted to plain + // compile error messages, without backtraces being reported by + // compile_exception. + { +  array bt; +  if (array|object e = catch (bt = get_backtrace (err))) +  handle_error (e); +  throw (CompileCallbackError (describe_error (err), bt)); + } +  + static void call_compile_warning (object handler, string file, +  string msg, mixed ... args) + { +  if (sizeof (args)) msg = sprintf (msg, @args); +  msg = trim_all_whites (msg); +  if (handler && handler->compile_warning) +  handler->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 = _static_modules.Builtin()->mutex(); + Builtin.mutex compilation_mutex = Builtin()->mutex();   #endif      static program low_findprog(string pname,    string ext,    object|void handler,    void|int mkobj)   {    program ret;    Stat s;    string fname=pname+ext;
pike.git/lib/master.pike.in:693:    (handler && handler->get_codec ||    get_codec)(fname, mkobj));    DEC_RESOLV_MSG_DEPTH();    resolv_debug ("low_findprog %s: dump decode ok\n", fname);    return programs[fname] = ret;       };    DEC_RESOLV_MSG_DEPTH();    resolv_debug ("low_findprog %s: dump decode failed\n", fname);    programs[fname] = no_value; -  if (handler && handler->compile_warning) { -  handler->compile_warning(oname, 0, -  sprintf("Decode failed:\n" -  "\t%s", describe_error(err))); -  } else { -  compile_warning(oname, 0, -  sprintf("Decode failed:\n" -  "\t%s", describe_error(err))); -  } +  call_compile_warning (handler, oname, +  "Decode failed: " + describe_error(err));    } else if (out_of_date_warning) { -  if (handler && handler->compile_warning) { -  handler->compile_warning(oname, 0, -  "Compiled file is out of date\n"); -  } else { -  compile_warning(oname, 0, "Compiled file is out of date\n"); +  call_compile_warning (handler, oname, +  "Compiled file is out of date");    }    }    } -  } +        resolv_debug ("low_findprog %s: compiling, mkobj: %O\n", fname, mkobj);    INC_RESOLV_MSG_DEPTH();    programs[fname]=ret=__empty_program(0, fname);    if ( mixed e=catch {    ret=compile_file(fname,    handler,    ret,    mkobj? (objects[ret]=__null_program()) : 0);    } )
pike.git/lib/master.pike.in:739:    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(\"%s\", \"%s\") => load_module(\"\")\n"    "%s\n", pname, ext, describe_backtrace(backtrace()) );    }    -  ret=load_module(fakeroot(fname)); +  if (array|object err = catch (ret = load_module(fakeroot(fname)))) +  compile_cb_rethrow (err);    resolv_debug ("low_findprog %s: loaded binary\n", fname);   #endif /* load_module */    }       AUTORELOAD_FINISH(ret,programs,fname);       resolv_debug("low_findprog %s: returning %O\n", fname, ret);       return programs[fname]=ret;    }
pike.git/lib/master.pike.in:860:   //! to aid the master finding the right program.   program cast_to_program(string pname,    string current_file,    object|void handler)   {    resolv_debug ("cast_to_program(%O, %O)\n", pname, current_file);    INC_RESOLV_MSG_DEPTH();    program ret = low_cast_to_program(pname, current_file, handler);    DEC_RESOLV_MSG_DEPTH();    resolv_debug ("cast_to_program(%O, %O) => %O\n", pname, current_file, ret); -  return ret; +  if (programp (ret)) return ret; +  error("Cast %O to program failed%s.\n", +  pname, +  (current_file && current_file!="-") ? sprintf(" in %O",current_file) : "");   }         //! This function is called when an error occurs that is not caught   //! with catch().   void handle_error(array(mixed)|object trace)   {    if(mixed x=catch {    werror(describe_backtrace(trace));    }) {
pike.git/lib/master.pike.in:913:    "compile_string",    "compile_file",    "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",    "getenv",    "putenv",      #ifdef GETCWD_CACHE    "cd",    "getcwd",   #endif   });   
pike.git/lib/master.pike.in:949:   {    object o = this_object();       foreach(master_efuns, string e)    if (o[e])    add_constant(e, o[e]);    else    error("Function %O is missing from master.pike.\n", e);       add_constant("strlen", sizeof); -  add_constant("write", _static_modules.___files()->_stdout->write); +  add_constant("write", Files()->_stdout->write);    - #define CO(X) add_constant(#X,_static_modules.Builtin.__backend->X) + #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");    add_module_path("¤share_prefix¤/modules");
pike.git/lib/master.pike.in:989:   //! 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)   {    resolv_debug ("handle_inherit(%O, %O)\n", pname, current_file);    INC_RESOLV_MSG_DEPTH(); -  program ret = low_cast_to_program(pname, current_file, handler); +  program ret = cast_to_program(pname, current_file, handler);    DEC_RESOLV_MSG_DEPTH();    resolv_debug ("handle_inherit(%O, %O) => %O\n", pname, current_file, ret);    return ret;   }      object low_cast_to_object(string oname, string current_file,    object|void current_handler)   {    program p;    object o;
pike.git/lib/master.pike.in:1019:   //! 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)   {    resolv_debug ("cast_to_object(%O, %O)\n", oname, current_file);    INC_RESOLV_MSG_DEPTH();    object o = low_cast_to_object(oname, current_file);    DEC_RESOLV_MSG_DEPTH();    resolv_debug ("cast_to_object(%O, %O) => %O\n", oname, current_file, o);    if (objectp (o)) return o; -  error("Cast '"+oname+"' to object failed"+ -  ((current_file && current_file!="-")?sprintf(" for '%s'",current_file):"")+".\n"); -  return 0; +  error("Cast %O to object failed%s.\n", +  oname, +  (current_file && current_file!="-") ? sprintf(" in %O",current_file) : "");   }      // Marker used for negative caching in module caches.   // FIXME: Won't this cause problems when inheriting "/master"?   static class ZERO_TYPE {};      //! Module node representing a single directory.   //!   //! @seealso   //! @[joinnode]
pike.git/lib/master.pike.in:1198:    return dirnode(fname, compilation_handler);    }    resolv_debug("dirnode(%O)->ind(%O) casting (object)%O\n",    dirname, index, fname);    // FIXME: cast_to_program() and cast_to_object()    // have lots of overhead to guess the proper    // filename. This overhead isn't needed in    // our cases, so we could make do with    // low_findprog() and the caches.    mixed ret; -  if (objectp(ret = cast_to_object(fname, 0, compilation_handler))) { +  if (objectp(ret = low_cast_to_object(fname, 0, compilation_handler))) {    // This assignment is needed for eg the Calendar module.    if (set_module) module = ret;    if(mixed tmp=ret->_module_value) ret=tmp;    DEC_RESOLV_MSG_DEPTH();    resolv_debug("dirnode(%O)->ind(%O) => found submodule %O:%O\n",    dirname, index, fname, ret);    return ret;    }    } else {    resolv_debug("dirnode(%O)->ind(%O) casting (program)%O\n",    dirname, index, fname);    program ret; -  if (ret = cast_to_program(fname, 0, compilation_handler)) { +  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);    return ret;    }    }    resolv_debug("dirnode(%O)->ind(%O) => failure for file %O\n",    dirname, index, fname);    }   
pike.git/lib/master.pike.in:1300:    }       cache[index] = zero_type(ret) ? ZERO_TYPE : ret;    return ret;    }       mixed safe_index(string index)    {    mixed err;    if (err = catch { return `[](index); }) { -  compile_warning(dirname+"."+fname, 0, -  sprintf("Compilation failed:\n" -  "%s\n", -  describe_backtrace(err))); +  call_compile_warning (compilation_handler, +  dirname+"."+fname, +  "Compilation failed: " + describe_error(err));    }    return UNDEFINED;    }       static int(0..1) _cache_full;    void fill_cache()    {   #if 0    werror(describe_backtrace(({ sprintf("Filling cache in dirnode %O\n",    dirname),    backtrace() })));   #endif    if (_cache_full) {    return;    }       // NOTE: We rely on side effects in `[]() and safe_index()    // to fill the cache. -  +  +  // Why shouldn't thrown errors be propagated here? /mast    if (module) {    map(indices(module), safe_index);    }       map(indices(file_paths), safe_index);    _cache_full = 1;    }       static array(string) _indices()    {
pike.git/lib/master.pike.in:1642:      #if constant(load_module)    if(master_file_stat(fakeroot(fullname+".so"))) {    o = fc[fullname] = low_cast_to_object(fullname, "/.", handler);    DEC_RESOLV_MSG_DEPTH();    resolv_debug ("findmodule(%O) => got .so object %O\n", fullname, o);    return o;    }   #endif    -  if (programp (o = cast_to_program(fullname, "/.", handler))) { +  if (programp (o = low_cast_to_program(fullname, "/.", handler))) {    DEC_RESOLV_MSG_DEPTH();    resolv_debug ("findmodule(%O) => got .pike program %O\n", fullname, o);    return fc[fullname] = o;    }       DEC_RESOLV_MSG_DEPTH();    resolv_debug ("findmodule(%O) => not found\n", fullname);    return fc[fullname] = 0;   }   
pike.git/lib/master.pike.in:2081:   //! and an array containing the environment variables on the same form as   //! a C program receives them.   void _main(array(string) orig_argv, array(string) env)   {    array(string) argv=copy_value(orig_argv);    int debug,trace,run_tool;    object tmp;    string postparseaction=0;       predefines = initial_predefines = -  _static_modules.Builtin()->_take_over_initial_predefines(); +  Builtin()->_take_over_initial_predefines();    _pike_file_name = orig_argv[0];   #if constant(thread_create)    _backend_thread = this_thread();   #endif       foreach(env, string a)    if( sscanf(a, "%s=%s", a, string b)==2 ) {   #ifdef __NT__    if(a=="") {    sscanf(b, "%s=%s", a, b);
pike.git/lib/master.pike.in:2487:    exit(10);    }    if(ret >=0) exit([int]ret);    _async=1;       while(1)    {    mixed err=catch    {    while(1) -  _static_modules.Builtin.__backend(3600.0); +  Builtin.__backend(3600.0);    };    master()->handle_error(err);    }   }      #if constant(thread_local)   object inhibit_compile_errors = thread_local();      void set_inhibit_compile_errors(mixed f)   {
pike.git/lib/master.pike.in:2551:   }      function(string:string) set_trim_file_name_callback(function(string:string) s)   {    function(string:string) f=_trim_file_name_cb;    _trim_file_name_cb=s;    return f;   }       - //! This function is called whenever a compiling error occurs. - //! Nothing strange about it. - //! Note that previous_object cannot be trusted in ths function, because - //! the compiler calls this function. + //! This function is called whenever a compile error occurs. @[line] + //! is zero for errors that aren't associated with any specific line. + //! @[err] is not newline terminated.   void compile_error(string file,int line,string err)   {    mixed val;    if(! (val = get_inhibit_compile_errors() ))    {    werror( "%s:%s:%s\n",trim_file_name(file),    line?(string)line:"-",err );    }    else if(objectp(val) ||    programp(val) ||
pike.git/lib/master.pike.in:2576:    {    if (objectp(val) && val->compile_error) {    val->compile_error(file, line, err);    } else {    val(file, line, err);    }    }   }       - //! This function is called whenever a compiling warning occurs. - //! Nothing strange about it. - //! Note that previous_object cannot be trusted in ths function, because - //! the compiler calls this function. + //! This function is called whenever a compile warning occurs. @[line] + //! is zero for warnings that aren't associated with any specific + //! line. @[err] is not newline terminated.   void compile_warning(string file,int line,string err)   {    mixed val;       if(!(val = get_inhibit_compile_errors() ))    {    if(want_warnings)    werror( "%s:%s: Warning: %s\n",trim_file_name(file),    line?(string)line:"-",err );    }
pike.git/lib/master.pike.in:2608:   //! compilation. Its message is also reported to @[compile_error] if   //! this function returns zero.   int compile_exception (array|object trace)   {    if (objectp (trace) &&    ( ([object]trace)->is_cpp_error ||    ([object]trace)->is_compilation_error))    // Errors thrown directly by cpp() and compile() are normally not    // interesting; they've already been reported to compile_error.    return 1; +  if (objectp (trace) && ([object] trace)->is_compile_callback_error) +  // Errors thrown by a compile callback that we should report as a +  // normal compile error, so let the caller do just that. +  return 0;    if (mixed val = get_inhibit_compile_errors()) {    if (objectp(val) && ([object]val)->compile_exception)    return ([function(object:int)]([object]val)    ->compile_exception)([object]trace);    }    else {    handle_error (trace);    return 1;    }    return 0;
pike.git/lib/master.pike.in:2659:   //! This function is called by cpp() when it wants to do   //! character code conversion.   string decode_charset(string data, string charset)   {    // werror(sprintf("decode_charset(%O, %O)\n", data, charset));       if (!_charset_mod) {    object mod = [object]resolv("Locale");       _charset_mod = [object](mod && mod["Charset"]); -  if (!_charset_mod) { -  compile_warning("-", 0, "No Locale.Charset module!"); -  return 0; +  if (!_charset_mod) +  compile_cb_error ("Cannot handle charset - no Locale.Charset module found.");    } -  } +     -  object decoder; +     -  catch { -  decoder = ([function(string:object)]_charset_mod->decoder)(charset); -  }; -  -  if (!decoder) { -  compile_warning("-", 0, sprintf("Unknown charset %O!", charset)); -  return 0; -  } +  if (mixed err = catch { +  object decoder = ([function(string:object)]_charset_mod->decoder)(charset);    return ([function(void:string)]([function(string:object)]decoder->    feed)(data)->drain)(); -  +  }) +  compile_cb_rethrow (err);   }            class Describer   {    int clipped=0;    int canclip=0;    mapping(mixed:int|string) ident = ([]);    int identcount = 0;
pike.git/lib/master.pike.in:3101:    (s=program_path_to_name(s, "object_program(", ")", "")))    return s;       if(object|program tmp=(function_object(p) || function_program(p))) {    if(s = function_name(p))    {    return describe_module(tmp) + s;    }    }    -  if(s=_static_modules.Builtin()->program_defined(p)) +  if(s=Builtin()->program_defined(p))    return EXPLODE_PATH(s)[-1];       return 0;   }      //!   string describe_function (function f)   {    if (!f) return 0;   
pike.git/lib/master.pike.in:3141:    }    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 - //! Returns a string containing a readable message that describes where - //! the backtrace was made. + //! Return a readable message that describes where the backtrace + //! @[trace] was made (by @[backtrace]).   //! - //! The argument @[trace] should normally be the return value from a call - //! to @[backtrace()], or a caught error. + //! 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.   //!   //! @seealso   //! @[backtrace()], @[describe_error()], @[catch()], @[throw()]   //!   string describe_backtrace(mixed trace, void|int linewidth)   {    int e; -  string ret = ""; +  string ret;    int backtrace_len=((int)getenv("PIKE_BACKTRACE_LEN")) || bt_max_string_len;       if(!linewidth)    {    linewidth=99999;    catch    { -  linewidth=[int]_static_modules.___files()->_stdin->tcgetattr()->columns; +  linewidth=[int]Files()->_stdin->tcgetattr()->columns;    };    if(linewidth<10) linewidth=99999;    }    -  if((arrayp(trace) && sizeof([array]trace)==2 && stringp(([array]trace)[0]))|| -  (objectp(trace) && ([object]trace)->is_generic_error)) -  { -  if (catch { -  ret = ([array(string)]trace)[0]; -  if(!stringp(ret)) -  ret = "No error message!\n"; -  trace = ([array]trace)[1]; -  }) { -  return "Error indexing backtrace!\n"; +  // 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)) +  // 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)) +  // 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 (describe_error (err)));    } -  if(!arrayp(trace)) -  return ret + "No backtrace.\n"; -  }else -  if (!arrayp (trace)) -  return sprintf ("Unrecognized backtrace format: %O\n", trace); +     -  +  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); +  } +  } +  +  else +  return sprintf ("<Invalid backtrace/error container: %O>\n", trace); +     {    Describer desc = Describer();    desc->identify_parts (trace);    array trace = [array]trace;       int end = 0;    if( (sizeof(trace)>1) &&    arrayp(trace[0]) &&    (sizeof([array]trace[0]) > 2) &&    (([array]trace[0])[2] == _main))
pike.git/lib/master.pike.in:3328:    frames += tail;    }       ret += frames * "";    }       return ret;   }      //! @appears describe_error - //! Returns only the error message from a backtrace. +    //! - //! If there is no error message in the backtrace, a fallback message - //! will be returned. + //! Return the error message from an error object or array (typically + //! caught by a @[catch]).   //! -  + //! 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 - //! @[backtrace()], @[describe_backtrace()] + //! @[describe_backtrace()], @[get_backtrace]   //! - string describe_error (mixed trace) + string describe_error (object|array err)   { -  if((arrayp(trace) && sizeof([array]trace)==2 && -  stringp(([array]trace)[0])) || -  (objectp(trace) && ([object]trace)->is_generic_error)) -  { -  if (catch { -  return ([array(string)]trace)[0] || "No error message.\n"; -  }) { -  return "Error indexing backtrace!\n"; +  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)) +  // 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 (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);   } -  return sprintf ("Backtrace is of unknown type %t!\n", trace); +  + //! @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)) +  // 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; + } +  +    #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" : \    sprintf ("%O", _v__)); \    return _v__; \   } while (0)   #else
pike.git/lib/master.pike.in:3555:    if (what->is_resolv_dirnode) {    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) {    ENC_MSG (" is a joinnode\n"); -  object modules = _static_modules.Builtin.array_iterator (what->joined_modules); +  object modules = Builtin.array_iterator (what->joined_modules);    object|mapping value;    check_dirnode:    if (modules && objectp (value = modules->value()) &&    value->is_resolv_dirnode) {    string name = program_path_to_name (value->dirname);    modules += 1;    foreach (modules;; value)    if (!objectp (value) || !value->is_resolv_dirnode ||    program_path_to_name (value->dirname) != name)    break check_dirnode;