ec94462002-05-01Martin Stjernholm // -*- Pike -*-
2f520e2002-04-28Martin Nilsson // // Master Control Program for Pike. // // This file is part of Pike. For copyright information see COPYRIGHT.
59e32d2002-06-01Martin Nilsson // Pike is distributed under GPL, LGPL and MPL. See the file COPYING // for more information.
2f520e2002-04-28Martin Nilsson //
fc2a322008-06-07Henrik Grubbström (Grubba) // $Id:,v 1.438 2008/06/06 22:29:46 grubba Exp $
c896b41998-04-29Henrik Grubbström (Grubba) 
a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
0fcf0c2004-03-05Martin Nilsson //#pragma strict_types
2f520e2002-04-28Martin Nilsson 
77e4f22002-07-09Martin Nilsson // Some programs destroys character pairs beginning with the currency // symbol when running in chinese locale.
47b4322002-06-28Martin Nilsson #if "¤/" != "\244/" #error " is corrupted." #endif
d5e23b2008-06-01Henrik Grubbström (Grubba) //! @appears predef::MasterObject //! //! Master control program for Pike. //! //! @seealso //! @[predef::master()], @[predef::replace_master()]
2f520e2002-04-28Martin Nilsson // --- Some configurable parameters
bec57d1999-09-06Fredrik Hübinette (Hubbe) #define PIKE_AUTORELOAD
2f520e2002-04-28Martin Nilsson #define GETCWD_CACHE #define FILE_STAT_CACHE
77e4f22002-07-09Martin Nilsson // This define is searched and replaced by bin/install.pike.
2f520e2002-04-28Martin Nilsson #undef PIKE_MODULE_RELOC #ifndef PIKE_WARNINGS
51a8f42002-05-15Henrik Grubbström (Grubba) #define PIKE_WARNINGS 1
2f520e2002-04-28Martin Nilsson #endif /* PIKE_WARNINGS */ // --- Global constants and variables
bec57d1999-09-06Fredrik Hübinette (Hubbe) 
c896b41998-04-29Henrik Grubbström (Grubba) // Used by describe_backtrace() et al. #if !defined(BT_MAX_STRING_LEN) || (BT_MAX_STRING_LEN <= 0) #undef BT_MAX_STRING_LEN
a858201999-10-15Fredrik Hübinette (Hubbe) #define BT_MAX_STRING_LEN 200
c896b41998-04-29Henrik Grubbström (Grubba) #endif /* !defined(BT_MAX_STRING_LEN) || (BT_MAX_STRING_LEN <= 0) */
d4fd0a1999-12-06Henrik Grubbström (Grubba) constant bt_max_string_len = BT_MAX_STRING_LEN;
6df5a52001-11-07Martin Nilsson //! @decl constant bt_max_string_len = 200
8a49852002-03-10Martin Stjernholm //! This constant contains the maximum length of a function entry in a //! backtrace. Defaults to 200 if no BT_MAX_STRING_LEN define has been
6df5a52001-11-07Martin Nilsson //! given.
97e5c72001-07-28Martin Nilsson 
401fa02002-12-02Martin Stjernholm // Enables the out of date warning in low_findprog().
e115cb1999-12-09Henrik Grubbström (Grubba) #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;
83ccb42004-04-11Henrik Grubbström (Grubba) // 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
131e462003-12-17Marcus Comstedt #if defined(__NT__) || defined(__amigaos__)
929cf72003-08-19Martin Nilsson #define PATH_SEPARATOR ";" #else #define PATH_SEPARATOR ":" #endif
61b41f2003-12-18Marcus Comstedt #ifdef __amigaos__ #define UPDIR "/" #else #define UPDIR "../" #endif
6df5a52001-11-07Martin Nilsson //! @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.
97e5c72001-07-28Martin Nilsson 
2f520e2002-04-28Martin Nilsson //! If not zero compilation warnings will be written out on stderr. int want_warnings = PIKE_WARNINGS;
df2c632000-08-02Henrik Grubbström (Grubba) 
2f520e2002-04-28Martin Nilsson //! int compat_major=-1;
4839dd2001-09-02Marcus Comstedt 
2f520e2002-04-28Martin Nilsson //! int compat_minor=-1;
f6da7b2004-06-27Martin Nilsson //! int show_if_constant_errors = 0;
2f520e2002-04-28Martin Nilsson  // --- Functions begin here.
677d262003-11-14Martin Stjernholm // Have to access some stuff without going through the resolver.
7d016d2008-03-26Henrik Grubbström (Grubba) private object(_static_modules.Builtin) Builtin = _static_modules.Builtin();
fd0fd72004-04-17Marcus Comstedt private constant Files = _static_modules.files;
677d262003-11-14Martin Stjernholm  #define Stat Files.Stat
2f520e2002-04-28Martin Nilsson #define capitalize(X) (upper_case((X)[..0])+(X)[1..])
7d016d2008-03-26Henrik Grubbström (Grubba) #define trim_all_whites(X) (Builtin.string_trim_all_whites (X))
c896b41998-04-29Henrik Grubbström (Grubba) 
d4140e2004-07-04Stephen R. van den Berg private function write = Files()->_stdout->write; private function werror = Files()->_stderr->write;
e3276e2004-07-04Stephen R. van den Berg 
3d21a62003-03-27Martin Stjernholm #ifdef RESOLV_DEBUG #if constant (thread_local) static object resolv_msg_depth = thread_local();
97f8142003-09-18Henrik Grubbström (Grubba) // 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))
3d21a62003-03-27Martin Stjernholm #else static int resolv_msg_depth; #define GET_RESOLV_MSG_DEPTH resolv_msg_depth #define INC_RESOLV_MSG_DEPTH() (++resolv_msg_depth) #define DEC_RESOLV_MSG_DEPTH() (--resolv_msg_depth) #endif void resolv_debug (string fmt, mixed... args) { string pad = " " * GET_RESOLV_MSG_DEPTH; if (sizeof (args)) fmt = sprintf (fmt, @args); if (fmt[-1] == '\n')
35320b2004-10-30Martin Stjernholm  fmt = pad + replace (fmt[..<1], "\n", "\n" + pad) + "\n";
3d21a62003-03-27Martin Stjernholm  else fmt = pad + replace (fmt, "\n", "\n" + pad);
7749332004-12-27Henrik Grubbström (Grubba)  if (!werror) werror = Files()->_stderr->write;
3d21a62003-03-27Martin Stjernholm  werror (fmt); } #else // !RESOLV_DEBUG #define INC_RESOLV_MSG_DEPTH() 0 #define DEC_RESOLV_MSG_DEPTH() 0 #define resolv_debug(X...) do {} while (0) #endif // !RESOLV_DEBUG
b784022008-05-28Henrik Grubbström (Grubba) // Some API compatibility stuff.
87ce122008-05-29Henrik Grubbström (Grubba) //! Pike 0.6 master compatibility interface. //! //! Most of the interface is implemented via mixin. //!
21c85e2008-06-01Henrik Grubbström (Grubba) //! @deprecated predef::MasterObject //!
87ce122008-05-29Henrik Grubbström (Grubba) //! @seealso
21c85e2008-06-01Henrik Grubbström (Grubba) //! @[get_compat_master()], @[master()], @[predef::MasterObject]
b784022008-05-28Henrik Grubbström (Grubba) static class Pike_0_6_master { int is_absolute_path(string p); array(string) explode_path(string p); string dirname(string x); string basename(string x); string describe_backtrace(array(mixed) trace); object low_cast_to_object(string oname, string current_file);
87ce122008-05-29Henrik Grubbström (Grubba)  extern array(string) pike_include_path; extern array(string) pike_module_path; extern array(string) pike_program_path; extern int want_warnings;
b784022008-05-28Henrik Grubbström (Grubba)  program compile_string(string data, void|string name); program compile_file(string file); #ifdef GETCWD_CACHE
87ce122008-05-29Henrik Grubbström (Grubba)  extern string current_path;
b784022008-05-28Henrik Grubbström (Grubba)  int cd(string s); string getcwd(); #endif string combine_path_with_cwd(string path); #ifdef FILE_STAT_CACHE
87ce122008-05-29Henrik Grubbström (Grubba)  extern int invalidate_time;
6f89182008-05-29Henrik Grubbström (Grubba)  extern mapping(string:multiset(string)) dir_cache; local array(mixed) master_file_stat(string x) {
8635822008-05-29Henrik Grubbström (Grubba)  Stat st = global::master_file_stat(x); return st && (array)st;
6f89182008-05-29Henrik Grubbström (Grubba)  }
b784022008-05-28Henrik Grubbström (Grubba) #endif
fc2a322008-06-07Henrik Grubbström (Grubba)  //! 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. local mapping(string:array(string)) environment; local string|mapping(string:string) getenv(string|void s) { if(!s) return [mapping(string:string)]aggregate_mapping( @(values(environment)*({}) ) ); #ifdef __NT__ s = lower_case(s); #endif return environment[s] && environment[s][1]; } local void putenv(string varname, string|void value) { // Try to update the real enviroment too, but ignore errors since // the fake environment could accommodate wide strings, strings // with NULs etc. catch {Builtin._putenv (varname, value);}; string index = varname; #ifdef __NT__ index = lower_case(varname); if (environment[index] && environment[index][0]) varname = environment[index][0]; #endif if (value) { environment[index] = ({ varname, value }); } else { m_delete(environment, index); } }
b784022008-05-28Henrik Grubbström (Grubba)  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; #if constant(_static_modules.Builtin.mutex)
87ce122008-05-29Henrik Grubbström (Grubba)  extern object compilation_mutex;
b784022008-05-28Henrik Grubbström (Grubba) #endif program cast_to_program(string pname, string current_file); void handle_error(array(mixed) trace);
21c85e2008-06-01Henrik Grubbström (Grubba)  //! Make a new instance of a class. //! //! @note //! This function should not be used. It is here for //! compatibility reasons only.
6f89182008-05-29Henrik Grubbström (Grubba)  local __deprecated__ object new(mixed prog, mixed ... args)
b784022008-05-28Henrik Grubbström (Grubba)  { if(stringp(prog)) prog=cast_to_program(prog,backtrace()[-2][0]); return prog(@args); }
21c85e2008-06-01Henrik Grubbström (Grubba) 
b784022008-05-28Henrik Grubbström (Grubba)  local constant mkmultiset = predef::mkmultiset;
6f89182008-05-29Henrik Grubbström (Grubba)  local __deprecated__(function) clone = new;
b784022008-05-28Henrik Grubbström (Grubba)  constant master_efuns = ({}); void create(); program handle_inherit(string pname, string current_file);
87ce122008-05-29Henrik Grubbström (Grubba)  extern mapping(program:object) objects;
b784022008-05-28Henrik Grubbström (Grubba)  object low_cast_to_object(string oname, string current_file); object cast_to_object(string oname, string current_file); class dirnode {}; class joinnode {};
87ce122008-05-29Henrik Grubbström (Grubba)  extern mapping(string:mixed) fc;
b784022008-05-28Henrik Grubbström (Grubba)  object findmodule(string fullname); mixed handle_import(string what, string|void current_file); local static 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); }
87ce122008-05-29Henrik Grubbström (Grubba)  extern string _pike_file_name; extern string _master_file_name;
b784022008-05-28Henrik Grubbström (Grubba)  void _main(array(string) orig_argv, array(string) env);
87ce122008-05-29Henrik Grubbström (Grubba)  extern mixed inhibit_compile_errors;
6f89182008-05-29Henrik Grubbström (Grubba)  void set_inhibit_compile_errors(mixed f);
b784022008-05-28Henrik Grubbström (Grubba)  string trim_file_name(string s); void compile_error(string file,int line,string err); void compile_warning(string file,int line,string err); string handle_include(string f, string current_file, int local_include); string read_include(string f);
6f89182008-05-29Henrik Grubbström (Grubba)  local __deprecated__ string stupid_describe(mixed m)
87ce122008-05-29Henrik Grubbström (Grubba)  { 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; } }
b784022008-05-28Henrik Grubbström (Grubba)  string describe_program(program p); string describe_backtrace(array(mixed) trace); class Codec {};
6f89182008-05-29Henrik Grubbström (Grubba)  object get_compat_master(int major, int minor); }
d5e23b2008-06-01Henrik Grubbström (Grubba) //! Pike 7.0 master compatibility interface. //! //! Most of the interface is implemented via mixin. //!
21c85e2008-06-01Henrik Grubbström (Grubba) //! @deprecated predef::MasterObject //!
d5e23b2008-06-01Henrik Grubbström (Grubba) //! @seealso
21c85e2008-06-01Henrik Grubbström (Grubba) //! @[get_compat_master()], @[master()], @[predef::MasterObject]
6f89182008-05-29Henrik Grubbström (Grubba) 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; #endif string master_read_file(); string normalize_path(string X); program cast_to_program(string pname, string current_file, object|void handler); void handle_error(array(mixed)|object trace); static 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 static 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) { return Pike_0_6_master::this; }
b784022008-05-28Henrik Grubbström (Grubba) }
d5e23b2008-06-01Henrik Grubbström (Grubba) //! Pike 7.2 master compatibility interface. //! //! Most of the interface is implemented via mixin. //!
21c85e2008-06-01Henrik Grubbström (Grubba) //! @deprecated predef::MasterObject //!
d5e23b2008-06-01Henrik Grubbström (Grubba) //! @seealso
21c85e2008-06-01Henrik Grubbström (Grubba) //! @[get_compat_master()], @[master()], @[predef::MasterObject]
6f89182008-05-29Henrik Grubbström (Grubba) static 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;
8635822008-05-29Henrik Grubbström (Grubba) #ifdef FILE_STAT_CACHE
6f89182008-05-29Henrik Grubbström (Grubba)  Stat master_file_stat(string x);
8635822008-05-29Henrik Grubbström (Grubba) #endif
6f89182008-05-29Henrik Grubbström (Grubba)  object low_cast_to_object(string oname, string current_file, object|void current_handler); object findmodule(string fullname, object|void handler); local static 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); static int clipped; static int canclip; static string stupid_describe(mixed m, int maxlen); static string stupid_describe_comma_list(array x, int maxlen); class Describer {}; string describe_function(function f); class CompatResolver {}; class Version {}; extern object currentversion; extern mapping(object:object) compat_handler_cache; object get_compilation_handler(int major, int minor);
8635822008-05-29Henrik Grubbström (Grubba)  local string _sprintf(int|void t) { return UNDEFINED; }
6f89182008-05-29Henrik Grubbström (Grubba)  object get_compat_master(int major, int minor) { if ((major > 0) || (minor > 6)) return Pike_7_0_master::this; return Pike_7_0_master::get_compat_master(major, minor); } }
d5e23b2008-06-01Henrik Grubbström (Grubba) //! Pike 7.4 master compatibility interface. //! //! Most of the interface is implemented via mixin. //!
21c85e2008-06-01Henrik Grubbström (Grubba) //! @deprecated predef::MasterObject //!
d5e23b2008-06-01Henrik Grubbström (Grubba) //! @seealso
21c85e2008-06-01Henrik Grubbström (Grubba) //! @[get_compat_master()], @[master()], @[predef::MasterObject]
6f89182008-05-29Henrik Grubbström (Grubba) static class Pike_7_4_master { inherit Pike_7_2_master; local static object Pike_7_4_compat_handler;
b3926d2008-06-05Martin Stjernholm  void error(string f, mixed ... args);
6f89182008-05-29Henrik Grubbström (Grubba)  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) && (minor > 0)) return Pike_7_2_master::this; return Pike_7_2_master::get_compat_master(major, minor); } }
d5e23b2008-06-01Henrik Grubbström (Grubba) //! Pike 7.6 master compatibility interface. //! //! Most of the interface is implemented via mixin. //!
21c85e2008-06-01Henrik Grubbström (Grubba) //! @deprecated predef::MasterObject //!
d5e23b2008-06-01Henrik Grubbström (Grubba) //! @seealso
21c85e2008-06-01Henrik Grubbström (Grubba) //! @[get_compat_master()], @[master()], @[predef::MasterObject]
6f89182008-05-29Henrik Grubbström (Grubba) static class Pike_7_6_master { inherit Pike_7_4_master; local static object Pike_7_6_compat_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); } return Pike_7_6_compat_handler->resolv(identifier, current_file); }
b3926d2008-06-05Martin Stjernholm  array get_backtrace (object|array err);
6f89182008-05-29Henrik Grubbström (Grubba)  object get_compat_master(int major, int minor) { if ((major == 7) && (minor > 2)) return Pike_7_4_master::this; return Pike_7_4_master::get_compat_master(major, minor); } }
d5e23b2008-06-01Henrik Grubbström (Grubba) //! Namespaces for compat masters. //! //! This inherit is used to provide compatibility namespaces //! for @[get_compat_master()]. //! //! @seealso //! @[get_compat_master()]
6f89182008-05-29Henrik Grubbström (Grubba) static inherit Pike_7_6_master;
b784022008-05-28Henrik Grubbström (Grubba) 
4f64a52002-05-22Martin Nilsson //! @appears error
01f7f32002-05-22Johan Sundström //! Throws an error. A more readable version of the code
e5ef062003-04-01Martin Nilsson //! @expr{throw( ({ sprintf(f, @@args), backtrace() }) )@}.
4f64a52002-05-22Martin Nilsson void error(string f, mixed ... args) { if (sizeof(args)) f = sprintf(f, @args);
35320b2004-10-30Martin Stjernholm  throw( ({ f, backtrace()[..<1] }) );
4f64a52002-05-22Martin Nilsson }
6df5a52001-11-07Martin Nilsson // FIXME: Should the pikeroot-things be private?
26f3da2000-07-11Fredrik Hübinette (Hubbe) #ifdef PIKE_FAKEROOT object o; string fakeroot(string s) { string tmp1=combine_path_with_cwd(s); #ifdef PIKE_FAKEROOT_OMIT
929cf72003-08-19Martin Nilsson  foreach(PIKE_FAKEROOT_OMIT/PATH_SEPARATOR, string x)
26f3da2000-07-11Fredrik Hübinette (Hubbe)  if(glob(x,tmp1)) return s; #endif return PIKE_FAKEROOT+tmp1; } #else #define fakeroot(X) X
2f520e2002-04-28Martin Nilsson #endif // PIKE_FAKEROOT
26f3da2000-07-11Fredrik Hübinette (Hubbe) 
4839dd2001-09-02Marcus Comstedt #ifdef PIKE_MODULE_RELOC string relocate_module(string s) {
57b52d2003-05-31Martin Stjernholm  if(s == "/${PIKE_MODULE_PATH}" || has_prefix (s, "/${PIKE_MODULE_PATH}/")) {
4839dd2001-09-02Marcus Comstedt  string tmp = s[21..]; foreach(pike_module_path, string path) { string s2 = fakeroot(sizeof(tmp)? combine_path(path, tmp) : path); if(master_file_stat(s2)) return s2; } } return fakeroot(s); } string unrelocate_module(string s) {
57b52d2003-05-31Martin Stjernholm  if(s == "/${PIKE_MODULE_PATH}" || has_prefix (s, "/${PIKE_MODULE_PATH}/"))
4839dd2001-09-02Marcus Comstedt  return s; foreach(pike_module_path, string path) if(s == path) return "/${PIKE_MODULE_PATH}"; else {
57b52d2003-05-31Martin Stjernholm  path = combine_path(path, ""); if(has_prefix (s, path)) return "/${PIKE_MODULE_PATH}/"+s[sizeof(path)..];
4839dd2001-09-02Marcus Comstedt  }
57b52d2003-05-31Martin Stjernholm  /* This is necessary to find compat modules... */ foreach(pike_module_path, string path) {
61b41f2003-12-18Marcus Comstedt  path = combine_path(path, UPDIR, "");
57b52d2003-05-31Martin Stjernholm  if(has_prefix (s, path))
61b41f2003-12-18Marcus Comstedt  return "/${PIKE_MODULE_PATH}/"+UPDIR+s[sizeof(path)..];
57b52d2003-05-31Martin Stjernholm  }
4839dd2001-09-02Marcus Comstedt  return s; }
57b52d2003-05-31Martin Stjernholm 
4839dd2001-09-02Marcus Comstedt #ifdef fakeroot #undef fakeroot #endif #define fakeroot relocate_module
2f520e2002-04-28Martin Nilsson #endif // PIKE_MODULE_RELOC
4839dd2001-09-02Marcus Comstedt 
26f3da2000-07-11Fredrik Hübinette (Hubbe) 
b07e962001-07-27Martin Nilsson //! @appears is_absolute_path
8f45692001-01-14Henrik Grubbström (Grubba) //! Check if a path @[p] is fully qualified (ie not relative). //! //! @returns //! Returns 1 if the path is absolute, 0 otherwise.
ca2b071998-03-28Henrik Grubbström (Grubba) int is_absolute_path(string p) {
61b41f2003-12-18Marcus Comstedt #ifdef __amigaos__
fbc9e32004-01-12Marcus Comstedt #define IS_ABSOLUTE_PATH(X) (search((X),":")>0)
61b41f2003-12-18Marcus Comstedt  return IS_ABSOLUTE_PATH(p); #else
ca2b071998-03-28Henrik Grubbström (Grubba) #ifdef __NT__ p=replace(p,"\\","/");
e49e542001-01-22Fredrik Hübinette (Hubbe)  if(sscanf(p,"%[a-zA-Z]:%*c",string s)==2 && sizeof(s)==1)
ca2b071998-03-28Henrik Grubbström (Grubba)  return 1;
471ed91998-04-24Fredrik Hübinette (Hubbe) #define IS_ABSOLUTE_PATH is_absolute_path #else
39033d2003-04-10Martin Stjernholm #define IS_ABSOLUTE_PATH(X) has_prefix((X),"/")
ca2b071998-03-28Henrik Grubbström (Grubba) #endif
39033d2003-04-10Martin Stjernholm  return has_prefix(p,"/");
61b41f2003-12-18Marcus Comstedt #endif
ca2b071998-03-28Henrik Grubbström (Grubba) }
4619bd2002-07-29Martin Nilsson #ifdef __NT__ #define EXPLODE_PATH(X) (replace((X),"\\","/")/"/") #else #define EXPLODE_PATH(X) ((X)/"/") #endif
b07e962001-07-27Martin Nilsson //! @appears explode_path
8f45692001-01-14Henrik Grubbström (Grubba) //! 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
0dd3c22004-01-12Marcus Comstedt //! not work on some operating systems. To turn the components back into //! a path again, use @[combine_path()].
8f45692001-01-14Henrik Grubbström (Grubba) //!
bbf4702000-04-10Henrik Grubbström (Grubba) array(string) explode_path(string p)
ca2b071998-03-28Henrik Grubbström (Grubba) {
0dd3c22004-01-12Marcus Comstedt #ifdef __amigaos__ int colon = search(reverse(p), ":"); if(colon >= 0)
35320b2004-10-30Martin Stjernholm  return ({ p[..<colon] }) + explode_path(p[<colon+1..]);
0dd3c22004-01-12Marcus Comstedt  array(string) r = p/"/";
35320b2004-10-30Martin Stjernholm  return replace(r[..<1], "", "/")+r[<0..];
0dd3c22004-01-12Marcus Comstedt #else array(string) r = EXPLODE_PATH(p); if(r[0] == "" && sizeof(p)) r[0] = "/"; return r; #endif
ca2b071998-03-28Henrik Grubbström (Grubba) }
b07e962001-07-27Martin Nilsson //! @appears dirname
77e4f22002-07-09Martin Nilsson //! 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>
943ea82003-12-19Marcus Comstedt //! <r><c>dirname("/a/b")</c><c>"/a"</c></r> //! <r><c>dirname("/a/")</c><c>"/a"</c></r>
77e4f22002-07-09Martin Nilsson //! <r><c>dirname("/a")</c><c>"/"</c></r> //! <r><c>dirname("/")</c><c>"/"</c></r> //! <r><c>dirname("")</c><c>""</c></r> //! </matrix>@}
8f45692001-01-14Henrik Grubbström (Grubba) //! //! @seealso //! @[basename()], @[explode_path()]
ca2b071998-03-28Henrik Grubbström (Grubba) string dirname(string x) {
77e4f22002-07-09Martin Nilsson  if(x=="") return "";
aea4b42003-12-19Marcus Comstedt #ifdef __amigaos__ array(string) tmp=x/":"; array(string) tmp2=tmp[-1]/"/";
35320b2004-10-30Martin Stjernholm  tmp[-1]=tmp2[..<1]*"/";
2510d42003-12-19Marcus Comstedt  if(sizeof(tmp2) >= 2 && tmp2[-2]=="") tmp[-1]+="/";
aea4b42003-12-19Marcus Comstedt  return tmp*":"; #else
afa1292000-02-19Martin Nilsson  array(string) tmp=EXPLODE_PATH(x);
bd22082002-07-29Martin Nilsson  if(x[0]=='/' && sizeof(tmp)<3) return "/";
35320b2004-10-30Martin Stjernholm  return tmp[..<1]*"/";
aea4b42003-12-19Marcus Comstedt #endif
ca2b071998-03-28Henrik Grubbström (Grubba) }
b07e962001-07-27Martin Nilsson //! @appears basename
8f45692001-01-14Henrik Grubbström (Grubba) //! Returns the last segment of a path. //! //! @seealso //! @[dirname()], @[explode_path()]
ca2b071998-03-28Henrik Grubbström (Grubba) string basename(string x) {
aea4b42003-12-19Marcus Comstedt #ifdef __amigaos__ return ((x/":")[-1]/"/")[-1]; #define BASENAME(X) ((((X)/":")[-1]/"/")[-1]) #else
afa1292000-02-19Martin Nilsson  array(string) tmp=EXPLODE_PATH(x);
ca2b071998-03-28Henrik Grubbström (Grubba)  return tmp[-1];
471ed91998-04-24Fredrik Hübinette (Hubbe) #define BASENAME(X) (EXPLODE_PATH(X)[-1])
aea4b42003-12-19Marcus Comstedt #endif }
ca2b071998-03-28Henrik Grubbström (Grubba) 
bec57d1999-09-06Fredrik Hübinette (Hubbe) #ifdef PIKE_AUTORELOAD int autoreload_on; int newest; #define AUTORELOAD_BEGIN() \ int ___newest=newest; \ newest=0
1a03e72005-11-09Henrik Grubbström (Grubba) #define AUTORELOAD_CHECK_FILE(X) do { \ if(autoreload_on) \ if(Stat s=master_file_stat(X)) \ if(s->mtime>newest) newest=[int]s->mtime; \ } while(0)
57b52d2003-05-31Martin Stjernholm #define AUTORELOAD_FINISH(VAR, CACHE, FILE) \ if(autoreload_on) { \ mixed val = CACHE[FILE]; \
1a03e72005-11-09Henrik Grubbström (Grubba)  if(!zero_type (val) && val != no_value && \ newest <= load_time[FILE]) { \
57b52d2003-05-31Martin Stjernholm  VAR = val; \ } \ } \
1a03e72005-11-09Henrik Grubbström (Grubba)  load_time[FILE] = newest; \
57b52d2003-05-31Martin Stjernholm  if(___newest > newest) newest=___newest;
bec57d1999-09-06Fredrik Hübinette (Hubbe)  mapping(string:int) load_time=([]); #else #define AUTORELOAD_CHECK_FILE(X) #define AUTORELOAD_BEGIN() #define AUTORELOAD_FINISH(VAR,CACHE,FILE)
2f520e2002-04-28Martin Nilsson #endif // PIKE_AUTORELOAD
a20af62000-09-26Fredrik Hübinette (Hubbe) 
b07e962001-07-27Martin Nilsson //! @appears compile_string
56cd002001-10-28Martin Nilsson //! Compile the Pike code in the string @[source] into a program.
e5ef062003-04-01Martin Nilsson //! If @[filename] is not specified, it will default to @expr{"-"@}.
8f45692001-01-14Henrik Grubbström (Grubba) //!
e5ef062003-04-01Martin Nilsson //! Functionally equal to @expr{@[compile](@[cpp](@[source], @[filename]))@}.
8f45692001-01-14Henrik Grubbström (Grubba) //! //! @seealso //! @[compile()], @[cpp()], @[compile_file()] //! program compile_string(string source, void|string filename,
c2e10c2003-11-18Martin Stjernholm  object|void handler, void|program p,
f6da7b2004-06-27Martin Nilsson  void|object o, void|int _show_if_constant_errors)
ca2b071998-03-28Henrik Grubbström (Grubba) {
6f46aa2007-06-12Martin Bähr  program ret = compile(cpp(source, filename||"-", 1, handler,
f6da7b2004-06-27Martin Nilsson  compat_major, compat_minor, (zero_type(_show_if_constant_errors)? show_if_constant_errors: _show_if_constant_errors)),
a20af62000-09-26Fredrik Hübinette (Hubbe)  handler, compat_major,
c2e10c2003-11-18Martin Stjernholm  compat_minor, p, o);
b73c652007-06-13Martin Bähr  if (source_cache) source_cache[ret] = source;
6f46aa2007-06-12Martin Bähr  return ret;
ca2b071998-03-28Henrik Grubbström (Grubba) }
97e5c72001-07-28Martin Nilsson //!
d8a6fc2000-03-25Fredrik Hübinette (Hubbe) string master_read_file(string file) {
677d262003-11-14Martin Stjernholm  object o=Files()->Fd();
da24482002-05-24Martin Nilsson  if( ([function(string, string : int)]o->open)(fakeroot(file),"r") ) return ([function(void : string)]o->read)();
d8a6fc2000-03-25Fredrik Hübinette (Hubbe)  return 0; }
ca2b071998-03-28Henrik Grubbström (Grubba) #ifdef GETCWD_CACHE
43293b2002-12-30Henrik Grubbström (Grubba) static string current_path;
ca2b071998-03-28Henrik Grubbström (Grubba) int cd(string s) { current_path=0; return predef::cd(s); } string getcwd() { return current_path || (current_path=predef::getcwd()); }
2f520e2002-04-28Martin Nilsson #endif // GETCWD_CACHE
ca2b071998-03-28Henrik Grubbström (Grubba) 
15af9c2003-12-19Marcus Comstedt string combine_path_with_cwd(string ... paths)
ca2b071998-03-28Henrik Grubbström (Grubba) {
15af9c2003-12-19Marcus Comstedt  return combine_path(IS_ABSOLUTE_PATH(paths[0])?"":getcwd(),@paths);
ca2b071998-03-28Henrik Grubbström (Grubba) } #ifdef FILE_STAT_CACHE #define FILE_STAT_CACHE_TIME 20 int invalidate_time; mapping(string:multiset(string)) dir_cache = ([]);
8ac7b02004-12-26Per Hedbor 
7749332004-12-27Henrik Grubbström (Grubba) array(string) master_get_dir(string|void x)
8ac7b02004-12-26Per Hedbor {
7749332004-12-27Henrik Grubbström (Grubba)  return get_dir(x);
8ac7b02004-12-26Per Hedbor }
61a4242000-08-27Mirar (Pontus Hagland) Stat master_file_stat(string x)
ca2b071998-03-28Henrik Grubbström (Grubba) {
da24482002-05-24Martin Nilsson  string dir = combine_path_with_cwd(x); string file = BASENAME(dir); dir = dirname(dir);
ca2b071998-03-28Henrik Grubbström (Grubba)  if(time() > invalidate_time) {
da24482002-05-24Martin Nilsson  dir_cache = ([]); invalidate_time = time()+FILE_STAT_CACHE_TIME;
ca2b071998-03-28Henrik Grubbström (Grubba)  }
da24482002-05-24Martin Nilsson  multiset(string) d = dir_cache[dir]; if( zero_type(d) )
ca2b071998-03-28Henrik Grubbström (Grubba)  {
8ac7b02004-12-26Per Hedbor  array(string) tmp = master_get_dir(dir);
da24482002-05-24Martin Nilsson  if(tmp)
ca2b071998-03-28Henrik Grubbström (Grubba)  {
fc398b2001-05-31Fredrik Hübinette (Hubbe) #ifdef __NT__
da24482002-05-24Martin Nilsson  tmp = map(tmp, lower_case);
fc398b2001-05-31Fredrik Hübinette (Hubbe) #endif
da24482002-05-24Martin Nilsson  d = dir_cache[dir] = aggregate_multiset(@tmp);
ca2b071998-03-28Henrik Grubbström (Grubba)  }
da24482002-05-24Martin Nilsson  else dir_cache[dir]=0;
ca2b071998-03-28Henrik Grubbström (Grubba)  }
eba0232004-01-13Martin Nilsson 
fc398b2001-05-31Fredrik Hübinette (Hubbe) #ifdef __NT__
da24482002-05-24Martin Nilsson  file = lower_case(file);
fc398b2001-05-31Fredrik Hübinette (Hubbe) #endif
ca2b071998-03-28Henrik Grubbström (Grubba)  if(d && !d[file]) return 0; return predef::file_stat(x); } #else #define master_file_stat file_stat
2f520e2002-04-28Martin Nilsson #endif // FILE_STAT_CACHE
ca2b071998-03-28Henrik Grubbström (Grubba) 
b3926d2008-06-05Martin Stjernholm  static mapping(string:string) environment; #ifdef __NT__ static void set_lc_env (mapping(string:string) env) { environment = ([]); foreach (env; string var; string val) environment[lower_case (var)] = val; } #endif //! @decl string getenv (string varname, void|int force_update) //! @decl mapping(string:string) getenv (void|int force_update)
43293b2002-12-30Henrik Grubbström (Grubba) //!
b3926d2008-06-05Martin Stjernholm //! Queries the environment variables. The first variant returns the //! value of a specific variable or zero if it doesn't exist in the //! environment. The second variant returns the whole environment as a //! mapping. Destructive opreations on the mapping will not affect the //! internal environment representation.
43293b2002-12-30Henrik Grubbström (Grubba) //!
b3926d2008-06-05Martin Stjernholm //! 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. //! //! Variable names and values cannot be wide strings nor contain //! @expr{'\0'@} characters. Variable names also cannot contain //! @expr{'='@} characters.
43293b2002-12-30Henrik Grubbström (Grubba) //! //! @note
b3926d2008-06-05Martin Stjernholm //! On NT the environment variable name is case insensitive.
5128432008-06-02Martin Stjernholm //!
b3926d2008-06-05Martin Stjernholm //! @seealso //! @[putenv()] string|mapping(string:string) getenv (void|int|string var, void|int force_update) { // Variants doesn't seem to work well yet. if (stringp (var)) { if (!environment || force_update) { #ifdef __NT__ set_lc_env (Builtin._getenv()); #else environment = Builtin._getenv(); #endif } #ifdef __NT__ return environment[lower_case (var)]; #else return environment[var]; #endif } else { force_update = var;
ca2b071998-03-28Henrik Grubbström (Grubba) 
b3926d2008-06-05Martin Stjernholm  mapping(string:string) res;
fc398b2001-05-31Fredrik Hübinette (Hubbe) 
b3926d2008-06-05Martin Stjernholm  if (force_update) { res = Builtin._getenv(); #ifdef __NT__ set_lc_env (res); #else environment = res + ([]); #endif } else { #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 } return res; } } void putenv (string varname, void|string value) //! Sets the environment variable @[varname] to @[value].
8f45692001-01-14Henrik Grubbström (Grubba) //!
b3926d2008-06-05Martin Stjernholm //! If @[value] is omitted or zero, the environment variable //! @[varname] will be removed.
8f45692001-01-14Henrik Grubbström (Grubba) //!
b3926d2008-06-05Martin Stjernholm //! @[varname] and @[value] cannot be wide strings nor contain //! @expr{'\0'@} characters. @[varname] also cannot contain //! @expr{'='@} characters.
8f45692001-01-14Henrik Grubbström (Grubba) //!
b3926d2008-06-05Martin Stjernholm //! @note //! On NT the environment variable name is case insensitive. //! //! @seealso //! @[getenv()]
a71f832001-11-13Tomas Nilsson //!
ca2b071998-03-28Henrik Grubbström (Grubba) {
b3926d2008-06-05Martin Stjernholm  Builtin._putenv (varname, value); if (environment) {
a71f832001-11-13Tomas Nilsson #ifdef __NT__
b3926d2008-06-05Martin Stjernholm  varname = lower_case (varname);
a71f832001-11-13Tomas Nilsson #endif
b3926d2008-06-05Martin Stjernholm  if (value) environment[varname] = value; else m_delete (environment, varname); }
df2c632000-08-02Henrik Grubbström (Grubba) }
fc398b2001-05-31Fredrik Hübinette (Hubbe) 
b07e962001-07-27Martin Nilsson //! @appears compile_file
fc398b2001-05-31Fredrik Hübinette (Hubbe) //! 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
e5ef062003-04-01Martin Nilsson //! @expr{@[compile_string](@[Stdio.read_file](@[filename]), @[filename])@}.
fc398b2001-05-31Fredrik Hübinette (Hubbe) //! //! @seealso //! @[compile()], @[compile_string()], @[cpp()] //! program compile_file(string filename, object|void handler, void|program p, void|object o) { AUTORELOAD_CHECK_FILE(filename);
0266592007-06-13Martin Bähr  return compile(cpp(master_read_file(filename),
fc398b2001-05-31Fredrik Hübinette (Hubbe)  filename, 1, handler, compat_major, compat_minor), handler, compat_major, compat_minor, p, o); }
b07e962001-07-27Martin Nilsson //! @appears normalize_path
c57eda2001-08-29Martin Nilsson //! Replaces "\" with "/" if runing on MS Windows. It is
c2d49b2002-02-14Martin Nilsson //! adviced to use @[System.normalize_path] instead.
c57eda2001-08-29Martin Nilsson string normalize_path( string path )
4c3f7d2000-04-13Per Hedbor { #ifndef __NT__
c57eda2001-08-29Martin Nilsson  return path;
4c3f7d2000-04-13Per Hedbor #else
c57eda2001-08-29Martin Nilsson  return replace(path,"\\","/");
4c3f7d2000-04-13Per Hedbor #endif }
ca2b071998-03-28Henrik Grubbström (Grubba) 
43293b2002-12-30Henrik Grubbström (Grubba) //! Mapping containing the cache of currently compiled files. //! //! This mapping currently has the following structure: //! @mapping //! @member program filename //! @endmapping
39979e2004-09-06Martin Stjernholm //! The filename path separator is / on both NT and UNIX.
43293b2002-12-30Henrik Grubbström (Grubba) //! //! @note
39979e2004-09-06Martin Stjernholm //! Special cases: The current master program is available under the //! name @expr{"/master"@}, and the program containing the @[main] //! function under @expr{"/main"@}.
e617062004-01-08Martin Nilsson mapping(string:program|NoValue) programs=(["/master":this_program]);
b73c652007-06-13Martin Bähr mapping(program:object) documentation = ([]); mapping(program:string) source_cache;
57b52d2003-05-31Martin Stjernholm  mapping (program:object|NoValue) objects=([
e617062004-01-08Martin Nilsson  this_program : this,
83da8e2008-05-14Henrik Grubbström (Grubba)  object_program(_static_modules): _static_modules,
57b52d2003-05-31Martin Stjernholm ]); mapping(string:object|NoValue) fc=([]); // Note: It's assumed that the mappings above never decrease in size
fb847c2004-06-17Martin Stjernholm // unless the reverse mappings above also are updated. no_value should // otherwise be used for entries that should be considered removed.
57b52d2003-05-31Martin Stjernholm  constant no_value = (<>); constant NoValue = typeof (no_value); // The reverse mapping for objects isn't only for speed; search() // doesn't work reliably there since it calls `==. static mapping(program:string) rev_programs = ([]); static mapping(object:program) rev_objects = ([]); static mapping(mixed:string) rev_fc = ([]); string programs_reverse_lookup (program prog) //! Returns the path for @[prog] in @[programs], if it got any. {
97f8142003-09-18Henrik Grubbström (Grubba)  // When running with trace, this function can get called // before __INIT has completed. if (!rev_programs) return UNDEFINED;
57b52d2003-05-31Martin Stjernholm  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)
1d918a2007-12-27Martin Nilsson //! Returns the program for @[obj], if known to the master.
57b52d2003-05-31Martin Stjernholm { if (sizeof (rev_objects) < sizeof (objects)) { foreach (objects; program prog; object|NoValue obj) if (obj == no_value)
ca1e632005-11-14Martin Nilsson  m_delete (rev_objects, obj);
57b52d2003-05-31Martin Stjernholm  else rev_objects[obj] = prog; } return rev_objects[obj]; } string fc_reverse_lookup (object obj) //! Returns the path for @[obj] in @[fc], if it got any. { if (sizeof (rev_fc) < sizeof (fc)) { foreach (fc; string path; mixed obj) if (obj == no_value) m_delete (fc, obj); else rev_fc[obj] = path; } return rev_fc[obj]; }
ca2b071998-03-28Henrik Grubbström (Grubba) 
6d926c1999-11-26Henrik Grubbström (Grubba) array(string) query_precompiled_names(string fname) { // Filenames of potential precompiled files in priority order.
8a49852002-03-10Martin Stjernholm #ifdef PRECOMPILED_SEARCH_MORE // Search for precompiled files in all module directories, not just // in the one where the source file is. This is useful when running // pike directly from the build directory. 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
6d926c1999-11-26Henrik Grubbström (Grubba)  return ({ fname + ".o" }); }
729acf2008-05-30Martin Stjernholm static class CompileCallbackError
677d262003-11-14Martin Stjernholm {
729acf2008-05-30Martin Stjernholm  inherit _static_modules.Builtin.GenericError;
677d262003-11-14Martin Stjernholm  constant is_generic_error = 1; constant is_compile_callback_error = 1;
729acf2008-05-30Martin Stjernholm  constant is_cpp_or_compilation_error = 1;
677d262003-11-14Martin Stjernholm } 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);
35320b2004-10-30Martin Stjernholm  throw (CompileCallbackError (msg, backtrace()[..<1]));
677d262003-11-14Martin Stjernholm } 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); }
6330192000-02-10Fredrik Hübinette (Hubbe) #if constant(_static_modules.Builtin.mutex) #define THREADED
7d016d2008-03-26Henrik Grubbström (Grubba) _static_modules.Builtin.mutex compilation_mutex = Builtin.mutex();
6330192000-02-10Fredrik Hübinette (Hubbe) #endif
61fdd72006-01-21Henrik Grubbström (Grubba) #ifdef __NT__ #define FIX_CASE(X) lower_case(X) #else #define FIX_CASE(X) (X) #endif /* __NT__ */ static string base_from_filename(string fname) { string low_name = FIX_CASE(fname); if (has_prefix(low_name, ".#")) return 0; if (has_suffix(low_name, ".pike") || has_suffix(low_name, ".pmod")) {
8a531a2006-11-04Martin Nilsson  return fname[..<5];
61fdd72006-01-21Henrik Grubbström (Grubba)  } if (has_suffix(low_name, ".so")) {
8a531a2006-11-04Martin Nilsson  return fname[..<3];
61fdd72006-01-21Henrik Grubbström (Grubba)  } return 0; } static 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; }
0266592007-06-13Martin Bähr //! 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)
1a84e52007-06-26Henrik Grubbström (Grubba) array(string) module_defined(object|program mod)
0266592007-06-13Martin Bähr { array files = ({});
1a84e52007-06-26Henrik Grubbström (Grubba)  if (programp(mod))
7d016d2008-03-26Henrik Grubbström (Grubba)  return ({ Builtin.program_defined([program]mod) });
9ef8fe2007-06-23Martin Bähr  array mods;
0266592007-06-13Martin Bähr  if (mod->is_resolv_joinnode) mods = mod->joined_modules; else mods = ({ mod }); foreach (mods;; object mod)
6f46aa2007-06-12Martin Bähr  {
0266592007-06-13Martin Bähr  if (mod->is_resolv_dirnode)
7d016d2008-03-26Henrik Grubbström (Grubba)  files += ({ Builtin.program_defined(object_program(mod->module)) });
6f46aa2007-06-12Martin Bähr  else
7d016d2008-03-26Henrik Grubbström (Grubba)  files += ({ Builtin.program_defined(object_program(mod)) });
6f46aa2007-06-12Martin Bähr  }
0266592007-06-13Martin Bähr  return files;
c475882007-06-11Martin Bähr }
b73c652007-06-13Martin Bähr //! Enable caching of sources from compile_string() void enable_source_cache() {
64ec5b2007-06-13Martin Bähr  if (!source_cache) source_cache = ([]);
b73c652007-06-13Martin Bähr }
c475882007-06-11Martin Bähr //! Show documentation for the item @[obj] //! //! @param obj //! The object for which the documentation should be shown //! //! @returns //! an AutoDoc object object show_doc(program|object|function obj) { object doc_extractor = main_resolv("Tools.AutoDoc.PikeExtractor.extractClass"); string child; program prog;
0266592007-06-13Martin Bähr 
c475882007-06-11Martin Bähr  if (programp(obj)) prog = obj; if (functionp(obj)) { prog = function_program(obj);
6f46aa2007-06-12Martin Bähr  child = ((describe_function(obj)||"")/"->")[-1];
c475882007-06-11Martin Bähr  } if (objectp(obj)) { if (obj->is_resolv_joinnode) obj = obj->joined_modules[0]; // FIXME: check for multiples if (obj->is_resolv_dirnode) prog = object_program(obj->module);
19d9422007-06-19Martin Bähr  else prog = object_program(obj);
c475882007-06-11Martin Bähr  }
0266592007-06-13Martin Bähr 
19d9422007-06-19Martin Bähr  if (prog && !documentation[prog] && doc_extractor)
c475882007-06-11Martin Bähr  {
b73c652007-06-13Martin Bähr  string source;
19d9422007-06-19Martin Bähr  if (source_cache && source_cache[prog])
b73c652007-06-13Martin Bähr  source = source_cache[prog];
19d9422007-06-19Martin Bähr  else
9ef8fe2007-06-23Martin Bähr  {
7d016d2008-03-26Henrik Grubbström (Grubba)  array sourceref = array_sscanf(Builtin.program_defined(prog),
9ef8fe2007-06-23Martin Bähr  "%s%[:]%[0-9]"); source = master_read_file(sourceref[0]); if (sizeof(sourceref[1]) && sizeof(sourceref[2])) { if (programp(prog)) child = ((describe_program(prog)||"")/".")[-1]; } }
19d9422007-06-19Martin Bähr 
b73c652007-06-13Martin Bähr  if (source) { catch { documentation[prog] = doc_extractor(source, sprintf("%O", prog)); }; //FIXME: handle this error somehow }
c475882007-06-11Martin Bähr  }
0266592007-06-13Martin Bähr 
b73c652007-06-13Martin Bähr  if (documentation[prog])
c475882007-06-11Martin Bähr  { if (child)
9ef8fe2007-06-23Martin Bähr  return documentation[prog]->findObject(child)||documentation[prog]->findChild(child);
c475882007-06-11Martin Bähr  else
b73c652007-06-13Martin Bähr  return documentation[prog];
c475882007-06-11Martin Bähr  } }
aa68b12001-03-19Fredrik Hübinette (Hubbe) static program low_findprog(string pname, string ext, object|void handler, void|int mkobj)
ca2b071998-03-28Henrik Grubbström (Grubba) { program ret;
61a4242000-08-27Mirar (Pontus Hagland)  Stat s;
ca2b071998-03-28Henrik Grubbström (Grubba)  string fname=pname+ext;
bec57d1999-09-06Fredrik Hübinette (Hubbe) 
68b7a22003-09-19Henrik Grubbström (Grubba)  resolv_debug("low_findprog(%O, %O, %O, %O)\n", pname, ext, handler, mkobj);
6330192000-02-10Fredrik Hübinette (Hubbe) #ifdef THREADED
3b11422000-02-13Henrik Grubbström (Grubba)  object key; // FIXME: The catch is needed, since we might be called in // a context when threads are disabled. // (compile() disables threads).
098c8a2000-03-30Henrik Grubbström (Grubba)  mixed err = catch {
3b11422000-02-13Henrik Grubbström (Grubba)  key=compilation_mutex->lock(2); };
098c8a2000-03-30Henrik Grubbström (Grubba)  if (err) {
2f520e2002-04-28Martin Nilsson  werror( "low_findprog: Caught spurious error:\n" "%s\n", describe_backtrace(err) );
098c8a2000-03-30Henrik Grubbström (Grubba)  }
6330192000-02-10Fredrik Hübinette (Hubbe) #endif
4839dd2001-09-02Marcus Comstedt #ifdef PIKE_MODULE_RELOC fname = unrelocate_module(fname); #endif
41ee482000-02-28Fredrik Hübinette (Hubbe) #ifdef __NT__
aedfbc2004-01-12Martin Nilsson  // Ugly kluge to work better with cygwin32 "/X:/" paths.
41ee482000-02-28Fredrik Hübinette (Hubbe)  if(getenv("OSTYPE")=="cygwin32") { string tmp=fname[..1]; if((tmp=="//" || tmp=="\\\\") && (fname[3]=='/' || fname[3]=='\\')) { if(!master_file_stat(fname)) { fname=fname[2..2]+":"+fname[3..]; } } } #endif
68065f2003-05-28Johan Sundström  if( (s=master_file_stat(fakeroot(fname))) && s->isreg )
ca2b071998-03-28Henrik Grubbström (Grubba)  {
1a03e72005-11-09Henrik Grubbström (Grubba) #ifdef PIKE_AUTORELOAD if(!autoreload_on || load_time[fname] >= s->mtime) #endif { if(!zero_type (ret=programs[fname]) && ret != no_value) { resolv_debug ("low_findprog %s: returning cached (no autoreload)\n", fname); return ret; } }
bec57d1999-09-06Fredrik Hübinette (Hubbe)  AUTORELOAD_BEGIN();
14fc641999-11-26Henrik Grubbström (Grubba) 
6e2ebb1999-12-28Martin Stjernholm #ifdef PIKE_AUTORELOAD
1a03e72005-11-09Henrik Grubbström (Grubba)  if (load_time[fname] >= s->mtime)
57b52d2003-05-31Martin Stjernholm  if (!zero_type (ret=programs[fname]) && ret != no_value) {
3d21a62003-03-27Martin Stjernholm  resolv_debug ("low_findprog %s: returning cached (autoreload)\n", fname);
401fa02002-12-02Martin Stjernholm  return ret; }
6e2ebb1999-12-28Martin Stjernholm #endif
14fc641999-11-26Henrik Grubbström (Grubba) 
ca2b071998-03-28Henrik Grubbström (Grubba)  switch(ext) { case "": case ".pike":
6d926c1999-11-26Henrik Grubbström (Grubba)  foreach(query_precompiled_names(fname), string oname) {
61a4242000-08-27Mirar (Pontus Hagland)  if(Stat s2=master_file_stat(fakeroot(oname)))
68065f2003-05-28Johan Sundström  { if(s2->isreg && s2->mtime >= s->mtime)
6d926c1999-11-26Henrik Grubbström (Grubba)  { mixed err=catch {
87ce122008-05-29Henrik Grubbström (Grubba)  object|program decoded;
6d926c1999-11-26Henrik Grubbström (Grubba)  AUTORELOAD_CHECK_FILE(oname);
3d21a62003-03-27Martin Stjernholm  resolv_debug ("low_findprog %s: decoding dumped\n", fname); INC_RESOLV_MSG_DEPTH();
87ce122008-05-29Henrik Grubbström (Grubba)  decoded = decode_value(master_read_file(oname), (handler && handler->get_codec || get_codec)(fname, mkobj, handler));
3d21a62003-03-27Martin Stjernholm  DEC_RESOLV_MSG_DEPTH(); resolv_debug ("low_findprog %s: dump decode ok\n", fname);
87ce122008-05-29Henrik Grubbström (Grubba)  if (decoded && decoded->this_program_does_not_exist) {
9d0e942005-04-15Henrik Grubbström (Grubba)  resolv_debug ("low_findprog %s: program claims not to exist\n", fname); return programs[fname] = 0; } else {
87ce122008-05-29Henrik Grubbström (Grubba)  if (objectp(decoded)) { resolv_debug("low_findprog %s: decoded object %O\n", fname, decoded); objects[ret = object_program(decoded)] = decoded; } else { ret = decoded; }
9d0e942005-04-15Henrik Grubbström (Grubba)  resolv_debug("low_findprog %s: returning %O\n", fname, ret); return programs[fname]=ret; }
6d926c1999-11-26Henrik Grubbström (Grubba)  };
3d21a62003-03-27Martin Stjernholm  DEC_RESOLV_MSG_DEPTH(); resolv_debug ("low_findprog %s: dump decode failed\n", fname);
57b52d2003-05-31Martin Stjernholm  programs[fname] = no_value;
677d262003-11-14Martin Stjernholm  call_compile_warning (handler, oname, "Decode failed: " + describe_error(err));
3abf3f2008-05-26Henrik Grubbström (Grubba)  // handle_error(err);
e115cb1999-12-09Henrik Grubbström (Grubba)  } else if (out_of_date_warning) {
677d262003-11-14Martin Stjernholm  call_compile_warning (handler, oname, "Compiled file is out of date");
10e16f1999-11-04Henrik Grubbström (Grubba)  }
b085961998-05-19Fredrik Hübinette (Hubbe)  }
471ed91998-04-24Fredrik Hübinette (Hubbe)  }
eba0232004-01-13Martin Nilsson 
3d21a62003-03-27Martin Stjernholm  resolv_debug ("low_findprog %s: compiling, mkobj: %O\n", fname, mkobj); INC_RESOLV_MSG_DEPTH();
401fa02002-12-02Martin Stjernholm  programs[fname]=ret=__empty_program(0, fname);
c2e10c2003-11-18Martin Stjernholm  AUTORELOAD_CHECK_FILE (fname); string src; if (array|object err = catch (src = master_read_file (fname))) { DEC_RESOLV_MSG_DEPTH(); resolv_debug ("low_findprog %s: failed to read file\n", fname); objects[ret] = no_value; ret=programs[fname]=0; // Negative cache. compile_cb_rethrow (err); }
aa68b12001-03-19Fredrik Hübinette (Hubbe)  if ( mixed e=catch {
c2e10c2003-11-18Martin Stjernholm  ret=compile_string(src, fname, handler, ret, mkobj? (objects[ret]=__null_program()) : 0); } )
ca2b071998-03-28Henrik Grubbström (Grubba)  {
3d21a62003-03-27Martin Stjernholm  DEC_RESOLV_MSG_DEPTH(); resolv_debug ("low_findprog %s: compilation failed\n", fname);
57b52d2003-05-31Martin Stjernholm  objects[ret] = no_value;
ab9d672003-03-08Henrik Grubbström (Grubba)  ret=programs[fname]=0; // Negative cache.
c46d682000-01-05Martin Stjernholm  throw(e);
ca2b071998-03-28Henrik Grubbström (Grubba)  }
3d21a62003-03-27Martin Stjernholm  DEC_RESOLV_MSG_DEPTH(); resolv_debug ("low_findprog %s: compilation ok\n", fname);
ca2b071998-03-28Henrik Grubbström (Grubba)  break;
20b5222004-03-22Martin Stjernholm 
ca2b071998-03-28Henrik Grubbström (Grubba) #if constant(load_module) case ".so":
caa3221998-04-15Henrik Grubbström (Grubba)  if (fname == "") {
20b5222004-03-22Martin Stjernholm  werror( "low_findprog(%O, %O) => load_module(\"\")\n"
2f520e2002-04-28Martin Nilsson  "%s\n", pname, ext, describe_backtrace(backtrace()) );
caa3221998-04-15Henrik Grubbström (Grubba)  }
26f3da2000-07-11Fredrik Hübinette (Hubbe) 
c2e10c2003-11-18Martin Stjernholm  if (array|object err = catch (ret = load_module(fakeroot(fname)))) { DEC_RESOLV_MSG_DEPTH(); resolv_debug ("low_findprog %s: failed to load binary\n", fname); objects[ret] = no_value; ret=programs[fname]=0; // Negative cache.
d58c972004-04-18Martin Stjernholm  if (objectp (err) && err->is_module_load_error)
20b5222004-03-22Martin Stjernholm  // Do not treat errors from dlopen(3) as exceptions since in // a dist we can have .so files that are dynamically linked // against libraries that don't exist on the system, and in // that case we should just treat the module as nonexisting. // // What we really want is to do this only for errors that // are due to nonexisting files, but the error reporting // from dlerror(3) doesn't allow us to tell those from other // errors. call_compile_warning (handler, fname,
d58c972004-04-18Martin Stjernholm  "Failed to load library: %s\n", err->reason);
20b5222004-03-22Martin Stjernholm  else compile_cb_rethrow (err);
c2e10c2003-11-18Martin Stjernholm  }
20b5222004-03-22Martin Stjernholm  else resolv_debug ("low_findprog %s: loaded binary\n", fname);
ca2b071998-03-28Henrik Grubbström (Grubba) #endif /* load_module */ }
bec57d1999-09-06Fredrik Hübinette (Hubbe)  AUTORELOAD_FINISH(ret,programs,fname);
6e2ebb1999-12-28Martin Stjernholm 
0453bf2004-03-22Martin Stjernholm  if (ret && ret->this_program_does_not_exist) { resolv_debug ("low_findprog %s: program says it doesn't exist\n", fname); return programs[fname] = 0; } else { resolv_debug("low_findprog %s: returning %O\n", fname, ret); return programs[fname]=ret; }
ca2b071998-03-28Henrik Grubbström (Grubba)  }
0453bf2004-03-22Martin Stjernholm 
3d21a62003-03-27Martin Stjernholm  resolv_debug ("low_findprog %s: file not found\n", fname);
6e2ebb1999-12-28Martin Stjernholm  return 0;
ca2b071998-03-28Henrik Grubbström (Grubba) }
eaa4da2001-10-04Fredrik Hübinette (Hubbe) //
a002d32002-03-01Martin Stjernholm // 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.
eaa4da2001-10-04Fredrik Hübinette (Hubbe) // void unregister(program p) {
87ce122008-05-29Henrik Grubbström (Grubba)  // werror("Unregistering %O...\n", p);
fb847c2004-06-17Martin Stjernholm  if(string fname=rev_programs[p] || search(programs,p)) {
3593292003-09-08Henrik Grubbström (Grubba)  resolv_debug("unregister %s\n", fname);
fb847c2004-06-17Martin Stjernholm  if (m_delete (rev_programs, p)) m_delete (programs, fname); else programs[fname] = no_value;
a002d32002-03-01Martin Stjernholm  fname = dirname (fname);
da24482002-05-24Martin Nilsson  object n;
57b52d2003-05-31Martin Stjernholm  if ( fname!="" && objectp (n = fc[fname]) )
a002d32002-03-01Martin Stjernholm  if (n->is_resolv_dirnode || n->is_resolv_joinnode)
1997b32005-07-13Henrik Grubbström (Grubba)  n->delete_value (p);
a002d32002-03-01Martin Stjernholm  }
fb847c2004-06-17Martin Stjernholm 
87ce122008-05-29Henrik Grubbström (Grubba)  object o = m_delete(objects, p);
fb847c2004-06-17Martin Stjernholm  if (objectp (o)) {
87ce122008-05-29Henrik Grubbström (Grubba)  m_delete(rev_objects, o);
fb847c2004-06-17Martin Stjernholm  }
c6cf602001-12-13Martin Stjernholm  foreach (fc; string name; mixed mod) if (objectp(mod) && object_program(mod) == p)
fb847c2004-06-17Martin Stjernholm  if (m_delete (rev_fc, mod)) m_delete (fc, name); else fc[name] = no_value;
eaa4da2001-10-04Fredrik Hübinette (Hubbe) }
aa68b12001-03-19Fredrik Hübinette (Hubbe) static program findprog(string pname, string ext, object|void handler, void|int mkobj)
ca2b071998-03-28Henrik Grubbström (Grubba) { switch(ext) { case ".pike": case ".so":
aa68b12001-03-19Fredrik Hübinette (Hubbe)  return low_findprog(pname,ext,handler, mkobj);
ca2b071998-03-28Henrik Grubbström (Grubba)  default: pname+=ext; return
aa68b12001-03-19Fredrik Hübinette (Hubbe)  low_findprog(pname,"", handler, mkobj) || low_findprog(pname,".pike", handler, mkobj) || low_findprog(pname,".so", handler, mkobj);
ca2b071998-03-28Henrik Grubbström (Grubba)  } }
aa68b12001-03-19Fredrik Hübinette (Hubbe) program low_cast_to_program(string pname, string current_file, object|void handler, void|int mkobj)
ca2b071998-03-28Henrik Grubbström (Grubba) { string ext; string nname;
7d016d2008-03-26Henrik Grubbström (Grubba)  //werror("low_cast_to_program(%O, %O, %O, %O)\n", // pname, current_file, handler, mkobj);
34241f2001-05-24Henrik Grubbström (Grubba) 
15af9c2003-12-19Marcus Comstedt  if(sscanf(reverse(BASENAME(pname)),"%s.%s",ext, nname))
ca2b071998-03-28Henrik Grubbström (Grubba)  { ext="."+reverse(ext);
35320b2004-10-30Martin Stjernholm  pname=pname[..<sizeof(ext)];
2f520e2002-04-28Martin Nilsson  } else {
ca2b071998-03-28Henrik Grubbström (Grubba)  ext=""; }
2f520e2002-04-28Martin Nilsson 
471ed91998-04-24Fredrik Hübinette (Hubbe)  if(IS_ABSOLUTE_PATH(pname))
ca2b071998-03-28Henrik Grubbström (Grubba)  {
57b52d2003-05-31Martin Stjernholm  program|NoValue prog = programs[pname];
c475882007-06-11Martin Bähr  if ((!zero_type(prog)) && (prog != no_value)) { return prog; }
61b41f2003-12-18Marcus Comstedt  pname=combine_path("",pname);
aa68b12001-03-19Fredrik Hübinette (Hubbe)  return findprog(pname,ext,handler,mkobj);
2f520e2002-04-28Martin Nilsson  } else {
ca2b071998-03-28Henrik Grubbström (Grubba)  string cwd; if(current_file) {
2f520e2002-04-28Martin Nilsson  cwd=dirname(current_file); } else {
ca2b071998-03-28Henrik Grubbström (Grubba)  cwd=getcwd(); }
aa68b12001-03-19Fredrik Hübinette (Hubbe)  if(program ret=findprog(combine_path(cwd,pname),ext,handler,mkobj))
ca2b071998-03-28Henrik Grubbström (Grubba)  return ret; foreach(pike_program_path, string path)
aa68b12001-03-19Fredrik Hübinette (Hubbe)  if(program ret=findprog(combine_path(path,pname),ext,handler,mkobj))
ca2b071998-03-28Henrik Grubbström (Grubba)  return ret; return 0; } }
aa68b12001-03-19Fredrik Hübinette (Hubbe) 
97e5c72001-07-28Martin Nilsson //! This function is called when the driver wants to cast a string //! to a program, this might be because of an explicit cast, an inherit //! or a implict cast. In the future it might receive more arguments, //! to aid the master finding the right program.
aa68b12001-03-19Fredrik Hübinette (Hubbe) program cast_to_program(string pname, string current_file, object|void handler) {
3d21a62003-03-27Martin Stjernholm  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);
677d262003-11-14Martin Stjernholm  if (programp (ret)) return ret; error("Cast %O to program failed%s.\n", pname, (current_file && current_file!="-") ? sprintf(" in %O",current_file) : "");
aa68b12001-03-19Fredrik Hübinette (Hubbe) }
97e5c72001-07-28Martin Nilsson //! This function is called when an error occurs that is not caught //! with catch().
aa84102003-12-06Martin Nilsson void handle_error(array|object trace)
ca2b071998-03-28Henrik Grubbström (Grubba) {
9d0e942005-04-15Henrik Grubbström (Grubba)  // NB: Use predef::trace() to modify trace level here. // predef::trace(2);
62e87b1998-04-14Fredrik Hübinette (Hubbe)  if(mixed x=catch { werror(describe_backtrace(trace));
d28a712001-07-02Henrik Grubbström (Grubba)  }) {
9f71092000-11-20Martin Stjernholm  // One reason for this might be too little stack space, which // easily can occur for "out of stack" errors. It should help to // tune up the STACK_MARGIN values in interpret.c then.
62e87b1998-04-14Fredrik Hübinette (Hubbe)  werror("Error in handle_error in master object:\n");
9f71092000-11-20Martin Stjernholm  if(catch {
9d0e942005-04-15Henrik Grubbström (Grubba)  // NB: Splited werror calls to retain some information // even if/when werror throws.
d28a712001-07-02Henrik Grubbström (Grubba)  catch { if (catch {
da24482002-05-24Martin Nilsson  string msg = [string]x[0]; array bt = [array]x[1];
9d0e942005-04-15Henrik Grubbström (Grubba)  werror("%s", msg); werror("%O\n", bt);
d28a712001-07-02Henrik Grubbström (Grubba)  }) { werror("%O\n", x); } }; werror("Original error:\n" "%O\n", trace);
aa73fc1999-10-21Fredrik Hübinette (Hubbe)  }) { werror("sprintf() failed to write error.\n"); }
62e87b1998-04-14Fredrik Hübinette (Hubbe)  }
9d0e942005-04-15Henrik Grubbström (Grubba)  // predef::trace(0);
ca2b071998-03-28Henrik Grubbström (Grubba) }
c5cc2d1998-04-29Henrik Grubbström (Grubba) /* This array contains the names of the functions * that a replacing master-object may want to override. */ constant master_efuns = ({
4f64a52002-05-22Martin Nilsson  "error",
c5cc2d1998-04-29Henrik Grubbström (Grubba)  "basename", "dirname", "is_absolute_path", "explode_path", "compile_string", "compile_file", "add_include_path", "remove_include_path", "add_module_path", "remove_module_path", "add_program_path", "remove_program_path", "describe_backtrace",
a66ff22000-01-11Martin Stjernholm  "describe_error",
677d262003-11-14Martin Stjernholm  "get_backtrace",
4c3f7d2000-04-13Per Hedbor  "normalize_path",
fb2dc02005-03-14Per Hedbor  "bool", "true", "false",
c5cc2d1998-04-29Henrik Grubbström (Grubba)  "getenv", "putenv", #ifdef GETCWD_CACHE "cd", "getcwd", #endif });
fb2dc02005-03-14Per Hedbor enum bool { false=0, true=1 };
e54fbc2006-04-22Henrik Grubbström (Grubba) //! Prefix for Pike-related C header files.
28c5382002-09-09Marcus Comstedt string include_prefix;
e54fbc2006-04-22Henrik Grubbström (Grubba) //! Prefix for autodoc files. string doc_prefix;
7a90f12003-01-26Martin Nilsson  //! @decl int strlen(string|multiset|array|mapping|object thing)
e378192003-01-20Martin Nilsson //! @appears strlen //! Alias for @[sizeof]. //! @deprecated sizeof
7a90f12003-01-26Martin Nilsson //! @decl int write(string fmt, mixed ... args)
e378192003-01-20Martin Nilsson //! @appears write //! Writes a string on stdout. Works just like @[Stdio.File.write] //! on @[Stdio.stdout].
d4140e2004-07-04Stephen R. van den Berg //! @decl int werror(string fmt, mixed ... args) //! @appears werror //! Writes a string on stderr. Works just like @[Stdio.File.write] //! on @[Stdio.stderr].
ca2b071998-03-28Henrik Grubbström (Grubba) /* Note that create is called before add_precompiled_program */
da494f2003-11-12Henrik Grubbström (Grubba) static void create()
ca2b071998-03-28Henrik Grubbström (Grubba) {
9066122002-11-28Martin Nilsson  foreach(master_efuns, string e)
fb2dc02005-03-14Per Hedbor  if (!zero_type(this[e]))
e617062004-01-08Martin Nilsson  add_constant(e, this[e]);
9066122002-11-28Martin Nilsson  else error("Function %O is missing from master.pike.\n", e);
c5cc2d1998-04-29Henrik Grubbström (Grubba) 
1554cc2007-09-03Henrik Grubbström (Grubba)  add_constant("__dirnode", dirnode); add_constant("__joinnode", joinnode);
c5cc2d1998-04-29Henrik Grubbström (Grubba)  add_constant("strlen", sizeof);
d4140e2004-07-04Stephen R. van den Berg  add_constant("write", write); add_constant("werror", werror);
b85b132004-12-26Per Hedbor  // 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("file_stat", lambda( string f, int|void d ) { return file_stat(f,d);} );
ca2b071998-03-28Henrik Grubbström (Grubba) 
677d262003-11-14Martin Stjernholm #define CO(X) add_constant(#X,Builtin.__backend->X)
87f9082001-03-12Fredrik Hübinette (Hubbe)  CO(call_out); CO(_do_call_outs); CO(find_call_out); CO(remove_call_out); CO(call_out_info);
e37a3e1999-10-09Fredrik Hübinette (Hubbe) #if "¤share_prefix¤"[0]!='¤'
2d8c832003-08-11Henrik Grubbström (Grubba)  // add path for architecture-independant files
e37a3e1999-10-09Fredrik Hübinette (Hubbe)  add_include_path("¤share_prefix¤/include"); add_module_path("¤share_prefix¤/modules"); #endif #if "¤lib_prefix¤"[0]!='¤' // add path for architecture-dependant files add_include_path("¤lib_prefix¤/include"); add_module_path("¤lib_prefix¤/modules"); #endif
28c5382002-09-09Marcus Comstedt  #if "¤include_prefix¤"[0]!='¤' include_prefix = "¤include_prefix¤"; #endif
e54fbc2006-04-22Henrik Grubbström (Grubba) #if "¤doc_prefix¤"[0]!='¤' doc_prefix = "¤doc_prefix¤"; #endif
110ff82007-01-24H. William Welliver III  #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");
98ed482007-07-31H. William Welliver III  add_module_path(__embedded_resource_directory + "/" + replace(uname()->machine, " ", "_") + "/modules");
110ff82007-01-24H. William Welliver III #endif
0418252003-10-30H. William Welliver III  system_module_path=pike_module_path;
22993b2008-06-06Henrik Grubbström (Grubba)  if (master() && master() != this_object()) {
f86cd22004-07-14Henrik Grubbström (Grubba)  // getenv() and putenv() will get confused if we don't do this.
b3926d2008-06-05Martin Stjernholm  // This is only for pike <= 7.6 compat.
22993b2008-06-06Henrik Grubbström (Grubba)  if (mapping e = (master()->environment || (master()->get_compat_master && master()->get_compat_master(7,6)->environment))) Pike_7_6_master::environment = e;
f86cd22004-07-14Henrik Grubbström (Grubba)  }
ca2b071998-03-28Henrik Grubbström (Grubba) }
97e5c72001-07-28Martin Nilsson  //! 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.
10e16f1999-11-04Henrik Grubbström (Grubba) program handle_inherit(string pname, string current_file, object|void handler)
ca2b071998-03-28Henrik Grubbström (Grubba) {
3d21a62003-03-27Martin Stjernholm  resolv_debug ("handle_inherit(%O, %O)\n", pname, current_file); INC_RESOLV_MSG_DEPTH();
677d262003-11-14Martin Stjernholm  program ret = cast_to_program(pname, current_file, handler);
3d21a62003-03-27Martin Stjernholm  DEC_RESOLV_MSG_DEPTH(); resolv_debug ("handle_inherit(%O, %O) => %O\n", pname, current_file, ret); return ret;
ca2b071998-03-28Henrik Grubbström (Grubba) }
34241f2001-05-24Henrik Grubbström (Grubba) object low_cast_to_object(string oname, string current_file, object|void current_handler)
ca2b071998-03-28Henrik Grubbström (Grubba) { program p; object o;
34241f2001-05-24Henrik Grubbström (Grubba)  p = low_cast_to_program(oname, current_file, current_handler, 1);
ca2b071998-03-28Henrik Grubbström (Grubba)  if(!p) return 0;
80f7142003-02-27Henrik Grubbström (Grubba)  // NB: p might be a function in a fake_object...
401fa02002-12-02Martin Stjernholm  if(!objectp (o=objects[p])) o=objects[p]=p();
ca2b071998-03-28Henrik Grubbström (Grubba)  return o; }
97e5c72001-07-28Martin Nilsson //! 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.
aa84102003-12-06Martin Nilsson object cast_to_object(string oname, string current_file, object|void current_handler)
ca2b071998-03-28Henrik Grubbström (Grubba) {
3d21a62003-03-27Martin Stjernholm  resolv_debug ("cast_to_object(%O, %O)\n", oname, current_file); INC_RESOLV_MSG_DEPTH();
aa84102003-12-06Martin Nilsson  object o = low_cast_to_object(oname, current_file, current_handler);
3d21a62003-03-27Martin Stjernholm  DEC_RESOLV_MSG_DEPTH(); resolv_debug ("cast_to_object(%O, %O) => %O\n", oname, current_file, o);
401fa02002-12-02Martin Stjernholm  if (objectp (o)) return o;
677d262003-11-14Martin Stjernholm  error("Cast %O to object failed%s.\n", oname, (current_file && current_file!="-") ? sprintf(" in %O",current_file) : "");
ca2b071998-03-28Henrik Grubbström (Grubba) }
97f8142003-09-18Henrik Grubbström (Grubba) // Marker used for negative caching in module caches. // FIXME: Won't this cause problems when inheriting "/master"? static class ZERO_TYPE {};
7d016d2008-03-26Henrik Grubbström (Grubba) static object Unicode;
97f8142003-09-18Henrik Grubbström (Grubba) //! Module node representing a single directory. //! //! @seealso //! @[joinnode]
eaa4da2001-10-04Fredrik Hübinette (Hubbe) class dirnode
ca2b071998-03-28Henrik Grubbström (Grubba) {
eaa4da2001-10-04Fredrik Hübinette (Hubbe)  string dirname;
97f8142003-09-18Henrik Grubbström (Grubba)  object|void compilation_handler;
1997b32005-07-13Henrik Grubbström (Grubba)  constant is_resolv_dirnode = 1;
401fa02002-12-02Martin Stjernholm  // objectp() is intentionally not used on the module object, to // allow a module to deny its own existence with `!.
97f8142003-09-18Henrik Grubbström (Grubba)  mixed module;
098c8a2000-03-30Henrik Grubbström (Grubba)  mapping(string:mixed) cache=([]);
97f8142003-09-18Henrik Grubbström (Grubba)  mapping(string:array(string)) file_paths = ([]);
ca2b071998-03-28Henrik Grubbström (Grubba) 
97f8142003-09-18Henrik Grubbström (Grubba) #ifdef __NT__ #define FIX_CASE(X) lower_case(X) #else #define FIX_CASE(X) (X) #endif /* __NT__ */ static string base_from_filename(string fname) {
4885f12003-09-19Henrik Grubbström (Grubba)  string low_name = FIX_CASE(fname);
58eb132008-03-20Henrik Grubbström (Grubba)  catch { // FIXME: Warn on failure? low_name = utf8_to_string(low_name);
236a4a2008-03-27Henrik Grubbström (Grubba)  if (Builtin.string_width(low_name) > 8) {
7d016d2008-03-26Henrik Grubbström (Grubba)  // We might need to normalize the string (cf MacOS X). // Load the Unicode module if it hasn't already been loaded. if (!Unicode) { Unicode = resolv("Unicode"); } low_name = Unicode.normalize(low_name, "NFC"); }
58eb132008-03-20Henrik Grubbström (Grubba)  };
4885f12003-09-19Henrik Grubbström (Grubba)  if (has_prefix(low_name, ".#")) return 0; if (has_suffix(low_name, ".pike") || has_suffix(low_name, ".pmod")) {
35320b2004-10-30Martin Stjernholm  return fname[..<5];
eaa4da2001-10-04Fredrik Hübinette (Hubbe)  }
4885f12003-09-19Henrik Grubbström (Grubba)  if (has_suffix(low_name, ".so")) {
35320b2004-10-30Martin Stjernholm  return fname[..<3];
97f8142003-09-18Henrik Grubbström (Grubba)  } return 0; } static 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;
eaa4da2001-10-04Fredrik Hübinette (Hubbe) 
97f8142003-09-18Henrik Grubbström (Grubba)  // FIXME: Warn here? return 0; } static void create(string d, object|void h) { resolv_debug ("dirnode(%O,%O) created\n",d,h); dirname=d; compilation_handler=h;
e617062004-01-08Martin Nilsson  fc[dirname]=this;
8ac7b02004-12-26Per Hedbor  array(string) files = sort(master_get_dir(d)||({}));
97f8142003-09-18Henrik Grubbström (Grubba)  if (!sizeof(d)) return; 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", d, h, sizeof(bases)); if (!sizeof(files)) return; foreach(files; int no; string fname) { fname = combine_path(dirname, fname); string base = bases[no]; if (base == "module") { // We need a module_checker. module = module_checker(); } array(string) paths = file_paths[base]; if (!paths) { // New entry. file_paths[base] = ({ fname }); continue; } // Multiple files. Order according to prio_from_filename(). // 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..];
e378192003-01-20Martin Nilsson  } }
14bb592000-05-06Fredrik Hübinette (Hubbe)  class module_checker { int `!() {
3d21a62003-03-27Martin Stjernholm  resolv_debug ("dirnode(%O)->module_checker()->`!()\n",dirname); INC_RESOLV_MSG_DEPTH();
80f7142003-02-27Henrik Grubbström (Grubba) 
5a847a2008-01-04Henrik Grubbström (Grubba)  if (mixed err = catch {
97f8142003-09-18Henrik Grubbström (Grubba)  // Look up module. if (module = cache["module"] || low_ind("module", 1)) {
80f7142003-02-27Henrik Grubbström (Grubba)  /* This allows for `[] to have side effects first time * it is called. (Specifically, the Calendar module uses
97f8142003-09-18Henrik Grubbström (Grubba)  * this).
80f7142003-02-27Henrik Grubbström (Grubba)  */ cache=([]); _cache_full=0; }
3d21a62003-03-27Martin Stjernholm  DEC_RESOLV_MSG_DEPTH();
97f8142003-09-18Henrik Grubbström (Grubba)  resolv_debug("dirnode(%O)->module_checker()->`!() => %s\n", dirname, !module ? "doesn't exist" : "exists");
3d21a62003-03-27Martin Stjernholm  return !module;
80f7142003-02-27Henrik Grubbström (Grubba)  }) {
4ce9832003-06-05Martin Stjernholm  //werror ("findmodule error: " + describe_backtrace (err));
80f7142003-02-27Henrik Grubbström (Grubba)  // findmodule() failed. This can occur due to circularities // between encode_value()'ed programs. // The error will then typically be: // "Cannot call functions in unfinished objects." // Pretend not to exist for now...
3d21a62003-03-27Martin Stjernholm  DEC_RESOLV_MSG_DEPTH();
97f8142003-09-18Henrik Grubbström (Grubba)  resolv_debug("dirnode(%O)->module_checker()->`!() => failure, doesn't exist\n", dirname);
80f7142003-02-27Henrik Grubbström (Grubba)  return 1;
eaa4da2001-10-04Fredrik Hübinette (Hubbe)  }
14bb592000-05-06Fredrik Hübinette (Hubbe)  }
52c5792000-05-23Fredrik Hübinette (Hubbe) 
eaa4da2001-10-04Fredrik Hübinette (Hubbe)  mixed `[](string index)
cd99712001-11-09Martin Stjernholm  {
3d21a62003-03-27Martin Stjernholm  resolv_debug ("dirnode(%O)->module_checker()[%O] => %O\n", dirname, index, module && module[index]); return module && module[index];
eaa4da2001-10-04Fredrik Hübinette (Hubbe)  }
52c5792000-05-23Fredrik Hübinette (Hubbe)  array(string) _indices() { if(module) return indices(module); } array _values() { if(module) return values(module); }
ca2b071998-03-28Henrik Grubbström (Grubba)  }
97f8142003-09-18Henrik Grubbström (Grubba)  static mixed low_ind(string index, int(0..1)|void set_module) { array(string) paths; if (!(paths = file_paths[index])) { DEC_RESOLV_MSG_DEPTH(); resolv_debug("dirnode(%O)->ind(%O) => no file match\n", dirname, index); return UNDEFINED; } foreach(paths, string fname) { resolv_debug("dirnode(%O)->ind(%O) Trying file %O...\n", dirname, index, fname); Stat stat = master_file_stat(fakeroot(fname)); if (!stat) { resolv_debug("dirnode(%O)->ind(%O) file %O disappeared!\n", dirname, index, fname); continue; } if (has_suffix(fname, ".pmod")) { if (stat->isdir) {
0488452008-02-07Martin Stjernholm  if (dirnode n = fc[fname]) { // Avoid duplicate dirnodes for the same dirs. This can // happen if the master is replaced, e.g. with master_76 // in 7.6/modules/__default.pmod. resolv_debug("dirnode(%O)->ind(%O) => found subdirectory %O, " "returning old dirnode\n", dirname, index, fname); return n; } resolv_debug("dirnode(%O)->ind(%O) => found subdirectory %O, " "creating new dirnode\n", dirname, index, fname); return fc[fname] = dirnode(fname, compilation_handler);
97f8142003-09-18Henrik Grubbström (Grubba)  } 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;
87ce122008-05-29Henrik Grubbström (Grubba)  if (ret = catch { 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; } }) { resolv_debug("dirnode(%O)->ind(%O) ==> Cast to object failed: %s\n", dirname, index, describe_backtrace(ret));
97f8142003-09-18Henrik Grubbström (Grubba)  } } else { resolv_debug("dirnode(%O)->ind(%O) casting (program)%O\n", dirname, index, fname);
fd0fd72004-04-17Marcus Comstedt  program|object ret;
677d262003-11-14Martin Stjernholm  if (ret = low_cast_to_program(fname, 0, compilation_handler)) {
97f8142003-09-18Henrik Grubbström (Grubba)  DEC_RESOLV_MSG_DEPTH(); resolv_debug("dirnode(%O)->ind(%O) => found subprogram %O:%O\n", dirname, index, fname, ret);
fd0fd72004-04-17Marcus Comstedt #if constant(load_module) if (has_suffix(fname, ".so")) { // This is compatible with 7.4 behaviour.
8c201a2004-04-17Marcus Comstedt  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(); ret = o; }
fd0fd72004-04-17Marcus Comstedt  if(mixed tmp=ret->_module_value) ret=tmp; } #endif
97f8142003-09-18Henrik Grubbström (Grubba)  return ret; } } resolv_debug("dirnode(%O)->ind(%O) => failure for file %O\n", dirname, index, fname); } resolv_debug("dirnode(%O)->ind(%O) => UNDEFINED\n", dirname, index); return UNDEFINED; }
098c8a2000-03-30Henrik Grubbström (Grubba)  static mixed ind(string index)
ca2b071998-03-28Henrik Grubbström (Grubba)  {
3d21a62003-03-27Martin Stjernholm  resolv_debug ("dirnode(%O)->ind(%O)\n", dirname, index); INC_RESOLV_MSG_DEPTH();
97f8142003-09-18Henrik Grubbström (Grubba)  if (_cache_full) { DEC_RESOLV_MSG_DEPTH(); resolv_debug("dirnode(%O)->ind(%O) => cache_full %O\n", dirname, index, cache[index]); return cache[index]; }
3d21a62003-03-27Martin Stjernholm  if(module)
e118831999-12-22Per Hedbor  {
cd99712001-11-09Martin Stjernholm  mixed o;
eaa4da2001-10-04Fredrik Hübinette (Hubbe) // _describe(module);
aa68b12001-03-19Fredrik Hübinette (Hubbe)  if(!zero_type(o=module[index])) {
3d21a62003-03-27Martin Stjernholm  DEC_RESOLV_MSG_DEPTH(); resolv_debug ("dirnode(%O)->ind(%O) => found %O\n", dirname, index, o);
aa68b12001-03-19Fredrik Hübinette (Hubbe)  return o; }
97f8142003-09-18Henrik Grubbström (Grubba)  resolv_debug ("dirnode(%O)->ind(%O) => not found in module\n", dirname, index);
a2faf61999-12-01Martin Stjernholm  }
4ce9832003-06-05Martin Stjernholm  else resolv_debug ("dirnode(%O)->ind(%O) => no module\n", dirname, index);
ca2b071998-03-28Henrik Grubbström (Grubba) 
97f8142003-09-18Henrik Grubbström (Grubba)  return low_ind(index);
ca2b071998-03-28Henrik Grubbström (Grubba)  }
098c8a2000-03-30Henrik Grubbström (Grubba)  mixed `[](string index)
ca2b071998-03-28Henrik Grubbström (Grubba)  { mixed ret;
eaa4da2001-10-04Fredrik Hübinette (Hubbe) #ifdef MODULE_TRACE
e378192003-01-20Martin Nilsson  werror("%*nDirnode(%O) cache[%O] ?????\n", sizeof(backtrace()),dirname,index);
eaa4da2001-10-04Fredrik Hübinette (Hubbe) #endif if(!zero_type(ret=cache[index]))
ca2b071998-03-28Henrik Grubbström (Grubba)  {
eaa4da2001-10-04Fredrik Hübinette (Hubbe) #ifdef MODULE_TRACE
3d21a62003-03-27Martin Stjernholm  werror("%*nDirnode(%O) cache[%O] => %O%s\n",
ab9d672003-03-08Henrik Grubbström (Grubba)  sizeof(backtrace()),dirname,index, ret, (ret != ZERO_TYPE)?"":" (zero_type)");
eaa4da2001-10-04Fredrik Hübinette (Hubbe) #endif
cd99712001-11-09Martin Stjernholm  if (ret != ZERO_TYPE) return ret;
ab9d672003-03-08Henrik Grubbström (Grubba) #ifdef MODULE_TRACE werror("%*nDirnode(%O) ZERO_TYPE!\n", sizeof(backtrace()),dirname); #endif
ca2b071998-03-28Henrik Grubbström (Grubba)  return UNDEFINED; }
1997b32005-07-13Henrik Grubbström (Grubba)  ret=ind(index);
dd7d452002-12-09Martin Stjernholm  // We might have gotten placeholder objects in the first pass // which must not be cached to the second.
ab9d672003-03-08Henrik Grubbström (Grubba)  if(ret == predef::__placeholder_object) { #ifdef MODULE_TRACE werror("%*nDirnode(%O) PLACE_HOLDER.\n", sizeof(backtrace()),dirname); #endif return ret; }
dd7d452002-12-09Martin Stjernholm 
cd99712001-11-09Martin Stjernholm  cache[index] = zero_type(ret) ? ZERO_TYPE : ret; return ret;
ca2b071998-03-28Henrik Grubbström (Grubba)  }
3e4b811998-10-16Henrik Grubbström (Grubba) 
97f8142003-09-18Henrik Grubbström (Grubba)  mixed safe_index(string index) { mixed err;
3abf3f2008-05-26Henrik Grubbström (Grubba)  resolv_debug ("dirnode(%O): %O...\n", dirname, index);
97f8142003-09-18Henrik Grubbström (Grubba)  if (err = catch { return `[](index); }) {
677d262003-11-14Martin Stjernholm  call_compile_warning (compilation_handler, dirname+"."+fname, "Compilation failed: " + describe_error(err));
97f8142003-09-18Henrik Grubbström (Grubba)  } return UNDEFINED; }
e378192003-01-20Martin Nilsson  static int(0..1) _cache_full;
3e4b811998-10-16Henrik Grubbström (Grubba)  void fill_cache() {
3d21a62003-03-27Martin Stjernholm #if 0
f4f08d1999-02-26Henrik Grubbström (Grubba)  werror(describe_backtrace(({ sprintf("Filling cache in dirnode %O\n", dirname), backtrace() })));
3d21a62003-03-27Martin Stjernholm #endif
3e4b811998-10-16Henrik Grubbström (Grubba)  if (_cache_full) { return; }
3abf3f2008-05-26Henrik Grubbström (Grubba)  resolv_debug ("dirnode(%O) => Filling cache...\n", dirname);
97f8142003-09-18Henrik Grubbström (Grubba)  // NOTE: We rely on side effects in `[]() and safe_index() // to fill the cache.
677d262003-11-14Martin Stjernholm  // Why shouldn't thrown errors be propagated here? /mast
3e4b811998-10-16Henrik Grubbström (Grubba)  if (module) {
3abf3f2008-05-26Henrik Grubbström (Grubba)  resolv_debug("dirnode(%O): module: %O, indices:%{%O, %}\n", dirname, module, indices(module));
97f8142003-09-18Henrik Grubbström (Grubba)  map(indices(module), safe_index);
3e4b811998-10-16Henrik Grubbström (Grubba)  }
97f8142003-09-18Henrik Grubbström (Grubba)  map(indices(file_paths), safe_index);
3abf3f2008-05-26Henrik Grubbström (Grubba)  _cache_full = (object_program(module) != __null_program); resolv_debug ("dirnode(%O) => Cache %s.\n", dirname, _cache_full?"full":"partially filled");
3e4b811998-10-16Henrik Grubbström (Grubba)  }
e378192003-01-20Martin Nilsson  static array(string) _indices()
3e4b811998-10-16Henrik Grubbström (Grubba)  { fill_cache();
eb801d2003-06-05Martin Stjernholm  // 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));
3e4b811998-10-16Henrik Grubbström (Grubba)  }
e378192003-01-20Martin Nilsson  static array(mixed) _values()
3e4b811998-10-16Henrik Grubbström (Grubba)  { fill_cache();
cd99712001-11-09Martin Stjernholm  return values(cache) - ({ZERO_TYPE});
3e4b811998-10-16Henrik Grubbström (Grubba)  }
52c5792000-05-23Fredrik Hübinette (Hubbe) 
a002d32002-03-01Martin Stjernholm  void delete_value (mixed val) {
97f8142003-09-18Henrik Grubbström (Grubba)  if (string name = search (cache, val)) {
a002d32002-03-01Martin Stjernholm  m_delete (cache, name);
97f8142003-09-18Henrik Grubbström (Grubba)  _cache_full = 0; }
a002d32002-03-01Martin Stjernholm  }
e378192003-01-20Martin Nilsson  static int(0..) _sizeof() { return sizeof(_values()); } static string _sprintf(int as) {
87ce122008-05-29Henrik Grubbström (Grubba)  return as=='O' && sprintf("master()->dirnode(%O:%O)", dirname, module && module);
e378192003-01-20Martin Nilsson  } }
ca2b071998-03-28Henrik Grubbström (Grubba) 
97f8142003-09-18Henrik Grubbström (Grubba) //! Module node holding possibly multiple directories, //! and optionally falling back to another level. //! //! @seealso //! @[dirnode]
94257b1998-10-16Henrik Grubbström (Grubba) class joinnode {
1997b32005-07-13Henrik Grubbström (Grubba)  constant is_resolv_joinnode = 1;
94257b1998-10-16Henrik Grubbström (Grubba)  array(object|mapping) joined_modules;
098c8a2000-03-30Henrik Grubbström (Grubba)  mapping(string:mixed) cache=([]);
94257b1998-10-16Henrik Grubbström (Grubba) 
97f8142003-09-18Henrik Grubbström (Grubba)  object compilation_handler; // NOTE: Uses the empty mapping as the default fallback // for simplified code. joinnode|mapping(mixed:int(0..0)) fallback_module = ([]);
52c5792000-05-23Fredrik Hübinette (Hubbe)  string _sprintf(int as)
97f8142003-09-18Henrik Grubbström (Grubba)  { return as=='O' && sprintf("master()->joinnode(%O)",joined_modules); }
52c5792000-05-23Fredrik Hübinette (Hubbe) 
da494f2003-11-12Henrik Grubbström (Grubba)  static void create(array(object|mapping) _joined_modules, object|void _compilation_handler, joinnode|void _fallback_module)
94257b1998-10-16Henrik Grubbström (Grubba)  { joined_modules = _joined_modules;
97f8142003-09-18Henrik Grubbström (Grubba)  compilation_handler = _compilation_handler; fallback_module = _fallback_module || ([]);
3d21a62003-03-27Martin Stjernholm  resolv_debug ("joinnode(%O) created\n", joined_modules);
94257b1998-10-16Henrik Grubbström (Grubba)  }
97f8142003-09-18Henrik Grubbström (Grubba)  void add_path(string path) { path = combine_path(getcwd(), path); dirnode node = fc[path] || (fc[path] = dirnode(path, compilation_handler)); if (sizeof(joined_modules) && joined_modules[0] == node) return; joined_modules = ({ node }) + (joined_modules - ({ node }));
da494f2003-11-12Henrik Grubbström (Grubba)  // FIXME: Propagate!
97f8142003-09-18Henrik Grubbström (Grubba)  } 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 || (node->dirname != path); });
da494f2003-11-12Henrik Grubbström (Grubba)  // FIXME: What about the cache? // FIXME: Propagate!
97f8142003-09-18Henrik Grubbström (Grubba)  }
098c8a2000-03-30Henrik Grubbström (Grubba)  static mixed ind(string index)
94257b1998-10-16Henrik Grubbström (Grubba)  {
3d21a62003-03-27Martin Stjernholm  resolv_debug ("joinnode(%O)->ind(%O)\n", joined_modules, index); INC_RESOLV_MSG_DEPTH();
94257b1998-10-16Henrik Grubbström (Grubba)  array(mixed) res = ({});
ca051c1999-11-23Per Hedbor  foreach(joined_modules, object|mapping o) {
94257b1998-10-16Henrik Grubbström (Grubba)  mixed ret;
ca051c1999-11-23Per Hedbor  if (!zero_type(ret = o[index])) {
97f8142003-09-18Henrik Grubbström (Grubba)  if (objectp(ret) &&
3ad5d62000-05-13Martin Stjernholm  (ret->is_resolv_dirnode || ret->is_resolv_joinnode))
ca051c1999-11-23Per Hedbor  {
8b307e1998-10-17Henrik Grubbström (Grubba)  // Only join directorynodes (or joinnodes).
97f8142003-09-18Henrik Grubbström (Grubba)  res += ({ ret }); } else {
3d21a62003-03-27Martin Stjernholm  DEC_RESOLV_MSG_DEPTH(); resolv_debug ("joinnode(%O)->ind(%O) => found %O\n", joined_modules, index, ret);
ca051c1999-11-23Per Hedbor  return (ret);
8b307e1998-10-17Henrik Grubbström (Grubba)  }
94257b1998-10-16Henrik Grubbström (Grubba)  } }
3d21a62003-03-27Martin Stjernholm 
97f8142003-09-18Henrik Grubbström (Grubba)  if (sizeof(res)) {
3d21a62003-03-27Martin Stjernholm  DEC_RESOLV_MSG_DEPTH();
97f8142003-09-18Henrik Grubbström (Grubba)  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]);
3d21a62003-03-27Martin Stjernholm  } DEC_RESOLV_MSG_DEPTH();
97f8142003-09-18Henrik Grubbström (Grubba)  resolv_debug ("joinnode(%O)->ind(%O) => not found. Trying fallback %O\n", joined_modules, index, fallback_module); return fallback_module[index];
94257b1998-10-16Henrik Grubbström (Grubba)  }
098c8a2000-03-30Henrik Grubbström (Grubba)  mixed `[](string index)
94257b1998-10-16Henrik Grubbström (Grubba)  {
098c8a2000-03-30Henrik Grubbström (Grubba)  mixed ret;
94257b1998-10-16Henrik Grubbström (Grubba)  if (!zero_type(ret = cache[index])) { if (ret != ZERO_TYPE) { return ret; } return UNDEFINED; }
1997b32005-07-13Henrik Grubbström (Grubba)  ret = ind(index);
dd7d452002-12-09Martin Stjernholm  // 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;
94257b1998-10-16Henrik Grubbström (Grubba)  if (zero_type(ret)) { cache[index] = ZERO_TYPE; } else { cache[index] = ret; } return ret; }
eb801d2003-06-05Martin Stjernholm 
098c8a2000-03-30Henrik Grubbström (Grubba)  static int _cache_full;
eb801d2003-06-05Martin Stjernholm 
3e4b811998-10-16Henrik Grubbström (Grubba)  void fill_cache() {
3d21a62003-03-27Martin Stjernholm #if 0
f4f08d1999-02-26Henrik Grubbström (Grubba)  werror(describe_backtrace(({ "Filling cache in joinnode\n", backtrace() })));
3d21a62003-03-27Martin Stjernholm #endif
3e4b811998-10-16Henrik Grubbström (Grubba)  if (_cache_full) { return; }
c084262000-02-04Henrik Grubbström (Grubba)  foreach(joined_modules, object|mapping|program o) {
3e4b811998-10-16Henrik Grubbström (Grubba)  foreach(indices(o), string index) { if (zero_type(cache[index])) { `[](index); } } }
a165032003-09-19Henrik Grubbström (Grubba)  foreach(indices(fallback_module), string index) { `[](index); }
3e4b811998-10-16Henrik Grubbström (Grubba)  _cache_full = 1; }
eb801d2003-06-05Martin Stjernholm 
3e4b811998-10-16Henrik Grubbström (Grubba)  array(string) _indices() { fill_cache();
eb801d2003-06-05Martin Stjernholm  // 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));
3e4b811998-10-16Henrik Grubbström (Grubba)  }
eb801d2003-06-05Martin Stjernholm 
3e4b811998-10-16Henrik Grubbström (Grubba)  array(mixed) _values() { fill_cache();
cd99712001-11-09Martin Stjernholm  return values(cache) - ({ZERO_TYPE});
3e4b811998-10-16Henrik Grubbström (Grubba)  }
a002d32002-03-01Martin Stjernholm  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))
1997b32005-07-13Henrik Grubbström (Grubba)  o->delete_value (val);
a002d32002-03-01Martin Stjernholm  else if (string name = mappingp (o) && search (o, val)) m_delete (o, name); } }
94257b1998-10-16Henrik Grubbström (Grubba) 
4ce9832003-06-05Martin Stjernholm  int `== (mixed other) { return objectp (other) && other->is_resolv_joinnode &&
1997b32005-07-13Henrik Grubbström (Grubba)  equal (mkmultiset (joined_modules), mkmultiset (other->joined_modules));
4ce9832003-06-05Martin Stjernholm  }
57b52d2003-05-31Martin Stjernholm  array(object) _encode() { return joined_modules; } void _decode (array(object) joined_modules) { this_program::joined_modules = joined_modules; } };
ca2b071998-03-28Henrik Grubbström (Grubba) 
97f8142003-09-18Henrik Grubbström (Grubba) joinnode handle_import(string path, string|void current_file, object|void current_handler) {
5dd1832003-12-18Marcus Comstedt #ifdef __amigaos__ if(path == ".") path = ""; #endif
97f8142003-09-18Henrik Grubbström (Grubba)  if(current_file) {
15af9c2003-12-19Marcus Comstedt  path = combine_path_with_cwd(dirname(current_file), path);
97f8142003-09-18Henrik Grubbström (Grubba)  } else { path = combine_path_with_cwd(path); } // FIXME: Need caching!!! #if 0 // FIXME: This caching strategy could be improved, // since it ignores module_nodes from the // ordinary module tree. if (module_node_cache[current_handler]) { if (module_node_cache[current_handler][path]) { return module_node_cache[current_handler][path]; } } else { module_node_cache[current_handler] = ([]); } module_node node = module_node_cache[current_handler][path] = module_node("import::"+path, 0, current_handler); #endif /* 0 */ joinnode node = joinnode(({}), current_handler); #ifdef PIKE_MODULE_RELOC // If we have PIKE_MODULE_RELOC enabled, // we might need to map to multiple directories. if(path == "/${PIKE_MODULE_PATH}" || has_prefix(path, "/${PIKE_MODULE_PATH}/")) { string tmp = path[21..]; foreach(pike_module_path, string prefix) {
1997b32005-07-13Henrik Grubbström (Grubba)  node->add_path(sizeof(tmp)? combine_path(prefix, tmp) : prefix);
97f8142003-09-18Henrik Grubbström (Grubba)  } } else #endif /* PIKE_MODULE_RELOC */
1997b32005-07-13Henrik Grubbström (Grubba)  node->add_path(path);
97f8142003-09-18Henrik Grubbström (Grubba)  return node; }
3593292003-09-08Henrik Grubbström (Grubba) program|object findmodule(string fullname, object|void handler)
ca2b071998-03-28Henrik Grubbström (Grubba) {
3593292003-09-08Henrik Grubbström (Grubba)  program|object o;
57b52d2003-05-31Martin Stjernholm 
3d21a62003-03-27Martin Stjernholm  resolv_debug ("findmodule(%O)\n", fullname);
57b52d2003-05-31Martin Stjernholm  if(!zero_type(o=fc[fullname]) && o != no_value)
ca2b071998-03-28Henrik Grubbström (Grubba)  {
3593292003-09-08Henrik Grubbström (Grubba)  if (objectp(o) || programp(o) || o != 0) {
3d21a62003-03-27Martin Stjernholm  resolv_debug ("findmodule(%O) => found %O (cached)\n", fullname, o); return o; } resolv_debug ("findmodule(%O) => not found (cached)\n", fullname); return UNDEFINED;
ca2b071998-03-28Henrik Grubbström (Grubba)  }
89b7162007-11-15Martin Stjernholm  if(Stat stat=master_file_stat(fakeroot(fullname)))
ca2b071998-03-28Henrik Grubbström (Grubba)  {
68065f2003-05-28Johan Sundström  if(stat->isdir) {
3d21a62003-03-27Martin Stjernholm  resolv_debug ("findmodule(%O) => new dirnode\n", fullname);
89b7162007-11-15Martin Stjernholm  return fc[fullname] = dirnode(fullname, handler); } #if constant (load_module) else if (has_suffix (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;
3d21a62003-03-27Martin Stjernholm  }
89b7162007-11-15Martin Stjernholm #endif
ca2b071998-03-28Henrik Grubbström (Grubba)  }
3d21a62003-03-27Martin Stjernholm  INC_RESOLV_MSG_DEPTH();
89b7162007-11-15Martin Stjernholm  if(objectp (o = low_cast_to_object(fullname, "/.", handler))) {
3d21a62003-03-27Martin Stjernholm  DEC_RESOLV_MSG_DEPTH(); resolv_debug ("findmodule(%O) => got object %O\n", fullname, o);
ca2b071998-03-28Henrik Grubbström (Grubba)  return fc[fullname]=o;
3d21a62003-03-27Martin Stjernholm  }
eba0232004-01-13Martin Nilsson 
677d262003-11-14Martin Stjernholm  if (programp (o = low_cast_to_program(fullname, "/.", handler))) {
3593292003-09-08Henrik Grubbström (Grubba)  DEC_RESOLV_MSG_DEPTH(); resolv_debug ("findmodule(%O) => got .pike program %O\n", fullname, o); return fc[fullname] = o; }
3d21a62003-03-27Martin Stjernholm  DEC_RESOLV_MSG_DEPTH(); resolv_debug ("findmodule(%O) => not found\n", fullname);
401fa02002-12-02Martin Stjernholm  return fc[fullname] = 0;
ca2b071998-03-28Henrik Grubbström (Grubba) }
97f8142003-09-18Henrik Grubbström (Grubba) #if 0
10e16f1999-11-04Henrik Grubbström (Grubba) mixed handle_import(string what, string|void current_file, object|void handler)
ca2b071998-03-28Henrik Grubbström (Grubba) {
afa1292000-02-19Martin Nilsson  string path;
ca2b071998-03-28Henrik Grubbström (Grubba)  if(current_file) {
15af9c2003-12-19Marcus Comstedt  path = combine_path_with_cwd(dirname(current_file), what);
57b1af2001-12-13Henrik Grubbström (Grubba)  } else { path = combine_path_with_cwd(what);
ca2b071998-03-28Henrik Grubbström (Grubba)  }
57b52d2003-05-31Martin Stjernholm  #if 0 // If we can't cache the dirnode when we got a handler, then // findmodule has to be broken too. Good caching is necessary for // module dumping. /mast
34241f2001-05-24Henrik Grubbström (Grubba)  if (handler) {
3d21a62003-03-27Martin Stjernholm  resolv_debug ("handle_import(%O, %O, %O) => new dirnode with handler\n", what, current_file, handler);
34241f2001-05-24Henrik Grubbström (Grubba)  return dirnode(path, handler); }
57b52d2003-05-31Martin Stjernholm #endif if(objectp (fc[path])) {
3d21a62003-03-27Martin Stjernholm  resolv_debug ("handle_import(%O, %O) => found %O (cached)\n", what, current_file, fc[path]); return fc[path]; } resolv_debug ("handle_import(%O, %O) => new dirnode\n", what, current_file);
2d8c832003-08-11Henrik Grubbström (Grubba) #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); 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);
cc2c071998-04-19Fredrik Hübinette (Hubbe) }
97f8142003-09-18Henrik Grubbström (Grubba) #endif /* 0 */
a20af62000-09-26Fredrik Hübinette (Hubbe)  multiset no_resolv = (<>);
b07e962001-07-27Martin Nilsson 
21c85e2008-06-01Henrik Grubbström (Grubba) //! Resolver of symbols not located in the program being compiled.
a20af62000-09-26Fredrik Hübinette (Hubbe) class CompatResolver
cc2c071998-04-19Fredrik Hübinette (Hubbe) {
21c85e2008-06-01Henrik Grubbström (Grubba)  //! Join node of the root modules for this resolver.
fd0fd72004-04-17Marcus Comstedt  joinnode root_module = joinnode(({instantiate_static_modules(predef::_static_modules)}));
97f8142003-09-18Henrik Grubbström (Grubba)  //! Lookup from handler module to corresponding root_module. mapping(object:joinnode) handler_root_modules = ([]);
94dc1b2003-10-30H. William Welliver III  //! The pike system module path, not including any set by the user.
0418252003-10-30H. William Welliver III  array(string) system_module_path=({}); //! The complete module search path
a20af62000-09-26Fredrik Hübinette (Hubbe)  array(string) pike_module_path=({});
0418252003-10-30H. William Welliver III  //! The complete include search path
97f8142003-09-18Henrik Grubbström (Grubba)  array(string) pike_include_path=({});
0418252003-10-30H. William Welliver III  //! The complete program search path
a20af62000-09-26Fredrik Hübinette (Hubbe)  array(string) pike_program_path=({});
0418252003-10-30H. William Welliver III 
da494f2003-11-12Henrik Grubbström (Grubba)  mapping(string:string) predefines = master()->initial_predefines;
a20af62000-09-26Fredrik Hübinette (Hubbe)  string ver;
97f8142003-09-18Henrik Grubbström (Grubba)  //! If we fail to resolv, try the fallback.
3593292003-09-08Henrik Grubbström (Grubba)  //! //! Typical configuration:
21c85e2008-06-01Henrik Grubbström (Grubba)  //! @pre{0.6->7.0->7.2-> ... ->master@}
97f8142003-09-18Henrik Grubbström (Grubba)  CompatResolver fallback_resolver;
3593292003-09-08Henrik Grubbström (Grubba) 
4619bd2002-07-29Martin Nilsson  //! The CompatResolver is initialized with a value that can be
6df5a52001-11-07Martin Nilsson  //! casted into a "%d.%d" string, e.g. a version object.
97f8142003-09-18Henrik Grubbström (Grubba)  //! //! It can also optionally be initialized with a fallback resolver.
da494f2003-11-12Henrik Grubbström (Grubba)  static void create(mixed version, CompatResolver|void fallback_resolver)
97f8142003-09-18Henrik Grubbström (Grubba)  { resolv_debug("CompatResolver(%O, %O)\n", version, fallback_resolver); ver=(string)version; #if 0 if (version) {
1997b32005-07-13Henrik Grubbström (Grubba)  root_module->symbol = ver + "::";
97f8142003-09-18Henrik Grubbström (Grubba)  } #endif if (CompatResolver::fallback_resolver = fallback_resolver) {
1997b32005-07-13Henrik Grubbström (Grubba)  root_module->fallback_module = fallback_resolver->root_module;
a20af62000-09-26Fredrik Hübinette (Hubbe)  }
97f8142003-09-18Henrik Grubbström (Grubba)  predefines = initial_predefines; }
a20af62000-09-26Fredrik Hübinette (Hubbe) 
8f45692001-01-14Henrik Grubbström (Grubba)  //! 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()] //!
a20af62000-09-26Fredrik Hübinette (Hubbe)  void add_include_path(string tmp) { tmp=normalize_path(combine_path_with_cwd(tmp)); pike_include_path-=({tmp}); pike_include_path=({tmp})+pike_include_path; }
8f45692001-01-14Henrik Grubbström (Grubba)  //! Remove a directory to search for include files. //! //! This function performs the reverse operation of @[add_include_path()]. //! //! @seealso //! @[add_include_path()] //!
a20af62000-09-26Fredrik Hübinette (Hubbe)  void remove_include_path(string tmp) { tmp=normalize_path(combine_path_with_cwd(tmp)); pike_include_path-=({tmp}); }
eba0232004-01-13Martin Nilsson 
8f45692001-01-14Henrik Grubbström (Grubba)  //! Add a directory to search for modules. //! //! This is the same as the command line option @tt{-M@}. //! //! @seealso //! @[remove_module_path()] //!
a20af62000-09-26Fredrik Hübinette (Hubbe)  void add_module_path(string tmp) { tmp=normalize_path(combine_path_with_cwd(tmp));
1997b32005-07-13Henrik Grubbström (Grubba)  root_module->add_path(tmp);
97f8142003-09-18Henrik Grubbström (Grubba)  pike_module_path = ({ tmp }) + (pike_module_path - ({ tmp }));
a20af62000-09-26Fredrik Hübinette (Hubbe)  }
eba0232004-01-13Martin Nilsson 
8f45692001-01-14Henrik Grubbström (Grubba)  //! Remove a directory to search for modules. //! //! This function performs the reverse operation of @[add_module_path()]. //! //! @seealso //! @[add_module_path()] //!
a20af62000-09-26Fredrik Hübinette (Hubbe)  void remove_module_path(string tmp) { tmp=normalize_path(combine_path_with_cwd(tmp));
1997b32005-07-13Henrik Grubbström (Grubba)  root_module->rem_path(tmp);
97f8142003-09-18Henrik Grubbström (Grubba)  pike_module_path -= ({ tmp });
a20af62000-09-26Fredrik Hübinette (Hubbe)  }
eba0232004-01-13Martin Nilsson 
8f45692001-01-14Henrik Grubbström (Grubba)  //! Add a directory to search for programs. //! //! This is the same as the command line option @tt{-P@}. //! //! @seealso //! @[remove_program_path()] //!
a20af62000-09-26Fredrik Hübinette (Hubbe)  void add_program_path(string tmp) { tmp=normalize_path(combine_path_with_cwd(tmp)); pike_program_path-=({tmp}); pike_program_path=({tmp})+pike_program_path; }
eba0232004-01-13Martin Nilsson 
8f45692001-01-14Henrik Grubbström (Grubba)  //! Remove a directory to search for programs. //! //! This function performs the reverse operation of @[add_program_path()]. //! //! @seealso //! @[add_program_path()] //!
a20af62000-09-26Fredrik Hübinette (Hubbe)  void remove_program_path(string tmp) { tmp=normalize_path(combine_path_with_cwd(tmp)); pike_program_path-=({tmp}); }
374c902001-12-20Martin Stjernholm  //! Add a define (without arguments) which will be implicitly //! defined in @[cpp] calls. void add_predefine (string name, string value) { predefines[name] = value; } //! Remove a define from the set that are implicitly defined in //! @[cpp] calls. void remove_predefine (string name) { m_delete (predefines, name); }
db77fa2002-12-14Martin Nilsson  //! Returns a mapping with the current predefines.
374c902001-12-20Martin Stjernholm  mapping get_predefines() { return predefines; }
fd0fd72004-04-17Marcus Comstedt  //! Instantiate static modules in the same way that dynamic modules //! are instantiated. static mapping(string:mixed) instantiate_static_modules(object|mapping static_modules) {
4b7c4c2004-04-17Marcus Comstedt  mapping(string:mixed) res = ([]), joins = ([]);
fd0fd72004-04-17Marcus Comstedt  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;
4b7c4c2004-04-17Marcus Comstedt  if(!has_value(name, '.')) res[name] = val; else { mapping(string:mixed) level = joins; string pfx; while(2 == sscanf(name, "%s.%s", pfx, name)) level = (level[pfx] || (level[pfx] = ([]))); level[name] = val; } } joinnode joinify(mapping m) { foreach(m; string n; mixed v) if(mappingp(v)) m[n]=joinify(v); return joinnode(({m})); }; foreach(joins; string n; mixed v) { if(mappingp(v)) v = joinify(v); if(res[n]) res[n] = joinnode(({res[n], v})); else res[n] = v;
fd0fd72004-04-17Marcus Comstedt  } return res; }
6df5a52001-11-07Martin Nilsson  //!
a20af62000-09-26Fredrik Hübinette (Hubbe)  mapping get_default_module() {
5b00002004-05-25Martin Stjernholm  resolv_debug ("%O->get_default_module()\n", this);
a20af62000-09-26Fredrik Hübinette (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 {
acd1632001-12-17Henrik Grubbström (Grubba)  if(resolv("__default") && (x=resolv("__default.all_constants"))) x=x();
a20af62000-09-26Fredrik Hübinette (Hubbe)  }; compat_major=saved_compat_major; compat_minor=saved_compat_minor; if(err) throw(err);
81c0e02008-06-06Henrik Grubbström (Grubba)  return x || all_constants();
a20af62000-09-26Fredrik Hübinette (Hubbe)  }
97f8142003-09-18Henrik Grubbström (Grubba)  // _static_modules -- default for global:: // current_handler->get_default_module()->_static_modules
3215c92003-05-15Henrik Grubbström (Grubba) 
97f8142003-09-18Henrik Grubbström (Grubba)  joinnode get_root_module(object|void current_handler) { if (!root_module) { error("get_root_module(%O): No default root module!\n", current_handler); } if (!current_handler) return root_module; joinnode node = handler_root_modules[current_handler]; if (node) return node;
34241f2001-05-24Henrik Grubbström (Grubba) 
97f8142003-09-18Henrik Grubbström (Grubba)  // 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"] || ([]);
ca2b071998-03-28Henrik Grubbström (Grubba)  }
94257b1998-10-16Henrik Grubbström (Grubba)  }
97f8142003-09-18Henrik Grubbström (Grubba) 
fd0fd72004-04-17Marcus Comstedt  node = joinnode(({ instantiate_static_modules(static_modules),
97f8142003-09-18Henrik Grubbström (Grubba)  // Copy relevant stuff from the root module.
1997b32005-07-13Henrik Grubbström (Grubba)  @filter(root_module->joined_modules,
97f8142003-09-18Henrik Grubbström (Grubba)  lambda(mixed x) { return objectp(x) && x->is_resolv_dirnode; }) }), current_handler,
1997b32005-07-13Henrik Grubbström (Grubba)  root_module->fallback_module);
97f8142003-09-18Henrik Grubbström (Grubba)  // FIXME: Is this needed? // Kluge to get _static_modules to work at top level.
1997b32005-07-13Henrik Grubbström (Grubba)  node->cache->_static_modules = static_modules;
97f8142003-09-18Henrik Grubbström (Grubba)  return node; } //! mixed resolv_base(string identifier, string|void current_file, object|void current_handler) { // werror("Resolv_base(%O)\n",identifier); return get_root_module(current_handler)[identifier]; }
6df5a52001-11-07Martin Nilsson 
100c3e2003-12-01Martin Nilsson  //! 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);
da22f12006-06-08Martin Stjernholm  if(zero_type(res)) error("Could not resolve %s.\n", identifier);
100c3e2003-12-01Martin Nilsson  return res; }
6df5a52001-11-07Martin Nilsson  //!
34241f2001-05-24Henrik Grubbström (Grubba)  mixed resolv(string identifier, string|void current_file, object|void current_handler)
97f8142003-09-18Henrik Grubbström (Grubba)  { resolv_debug("resolv(%O, %O)\n",identifier, current_file); INC_RESOLV_MSG_DEPTH();
a20af62000-09-26Fredrik Hübinette (Hubbe) 
97f8142003-09-18Henrik Grubbström (Grubba)  // 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; }
26ece22001-06-18Henrik Grubbström (Grubba) 
97f8142003-09-18Henrik Grubbström (Grubba)  if (current_file && !stringp(current_file)) {
15cb2e2008-02-28Henrik Grubbström (Grubba)  error("resolv(%O, %O, %O): current_file is not a string!\n", identifier, current_file, current_handler);
97f8142003-09-18Henrik Grubbström (Grubba)  }
eaa4da2001-10-04Fredrik Hübinette (Hubbe) 
15cb2e2008-02-28Henrik Grubbström (Grubba)  array(string) tmp = identifier/"::"; mixed ret; if (sizeof(tmp) > 1) { string scope = tmp[0];
9eee962008-05-20Henrik Grubbström (Grubba)  tmp = tmp[1]/".";
15cb2e2008-02-28Henrik Grubbström (Grubba)  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) {
9eee962008-05-20Henrik Grubbström (Grubba)  mixed mod = ret->get_default_module(); if (!zero_type(mod = mod[tmp[0]])) { ret = mod;
15cb2e2008-02-28Henrik Grubbström (Grubba)  } else {
9eee962008-05-20Henrik Grubbström (Grubba)  ret = ret->resolv(tmp[0]);
15cb2e2008-02-28Henrik Grubbström (Grubba)  }
9eee962008-05-20Henrik Grubbström (Grubba)  tmp = tmp[1..];
15cb2e2008-02-28Henrik Grubbström (Grubba)  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); tmp = tmp[1..]; } foreach(tmp,string index) {
7749332004-12-27Henrik Grubbström (Grubba)  resolv_debug("indexing %O with %O...\n", ret, index);
3abf3f2008-05-26Henrik Grubbström (Grubba)  resolv_debug("indices(%O): %O\n", ret, indices(ret));
97f8142003-09-18Henrik Grubbström (Grubba)  if (zero_type(ret)) break; ret = ret[index]; } DEC_RESOLV_MSG_DEPTH();
3c6f582002-05-24Martin Stjernholm #ifdef RESOLV_DEBUG
97f8142003-09-18Henrik Grubbström (Grubba)  if (zero_type (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);
3c6f582002-05-24Martin Stjernholm #endif /* RESOLV_DEBUG */
97f8142003-09-18Henrik Grubbström (Grubba)  return ret; }
a20af62000-09-26Fredrik Hübinette (Hubbe) 
b784022008-05-28Henrik Grubbström (Grubba) 
9a61da2004-04-20Martin Nilsson  //! 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
a20af62000-09-26Fredrik Hübinette (Hubbe)  string handle_include(string f, string current_file, int local_include)
97f8142003-09-18Henrik Grubbström (Grubba)  { if(local_include)
a20af62000-09-26Fredrik Hübinette (Hubbe)  {
0ee5c62004-01-12Martin Nilsson  if(IS_ABSOLUTE_PATH(f)) return combine_path(f);
15af9c2003-12-19Marcus Comstedt  return combine_path_with_cwd(dirname(current_file), f);
97f8142003-09-18Henrik Grubbström (Grubba)  } else { foreach(pike_include_path, string path)
a20af62000-09-26Fredrik Hübinette (Hubbe)  {
97f8142003-09-18Henrik Grubbström (Grubba)  path=combine_path(path,f); if(master_file_stat(fakeroot(path))) return path;
a20af62000-09-26Fredrik Hübinette (Hubbe)  }
97f8142003-09-18Henrik Grubbström (Grubba)  if (fallback_resolver) { return fallback_resolver->handle_include(f, current_file,
3593292003-09-08Henrik Grubbström (Grubba)  local_include);
a20af62000-09-26Fredrik Hübinette (Hubbe)  } }
97f8142003-09-18Henrik Grubbström (Grubba)  // Failed. return 0; }
6df5a52001-11-07Martin Nilsson  //!
a20af62000-09-26Fredrik Hübinette (Hubbe)  string read_include(string f)
97f8142003-09-18Henrik Grubbström (Grubba)  {
c2e10c2003-11-18Martin Stjernholm  AUTORELOAD_CHECK_FILE(f); if (array|object err = catch { return master_read_file (f); }) compile_cb_rethrow (err);
97f8142003-09-18Henrik Grubbström (Grubba)  }
a20af62000-09-26Fredrik Hübinette (Hubbe) 
9852f72002-12-03Martin Nilsson  string _sprintf(int t)
97f8142003-09-18Henrik Grubbström (Grubba)  { return t=='O' && sprintf("CompatResolver(%O)",ver); }
7c11f41999-10-04Fredrik Hübinette (Hubbe) }
a20af62000-09-26Fredrik Hübinette (Hubbe) inherit CompatResolver;
0e66132003-09-20Martin Nilsson //!
97f8142003-09-18Henrik Grubbström (Grubba) class Pike06Resolver { inherit CompatResolver; //! 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); } }
97e5c72001-07-28Martin Nilsson //! These are useful if you want to start other Pike processes //! with the same options as this one was started with.
bfa62b1998-04-30Henrik Grubbström (Grubba) string _pike_file_name;
ac51841998-04-29Henrik Grubbström (Grubba) string _master_file_name;
b1d7d92002-01-07Martin Nilsson // Gets set to 1 if we're in async-mode (script->main() returned <0) private int(0..1) _async=0;
53a32a2000-06-04Francesco Chemolli 
b1d7d92002-01-07Martin Nilsson //! Returns 1 if we´re in async-mode, e.g. if the main method has //! returned a negative number. int(0..1) asyncp() {
53a32a2000-06-04Francesco Chemolli  return _async; }
45c7262001-04-17Mirar (Pontus Hagland) #if constant(thread_create) // this must be done in __init if someone inherits the master static object _backend_thread=this_thread();
97e5c72001-07-28Martin Nilsson  //! The backend_thread() function is useful to determine if you are //! the backend thread - important when doing async/sync protocols. //! This method is only available if thread_create is present.
45c7262001-04-17Mirar (Pontus Hagland) object backend_thread() { return _backend_thread; } #endif
70e2ca2003-01-01Martin Nilsson 
97f8142003-09-18Henrik Grubbström (Grubba) mapping(string:string) initial_predefines = ([]);
aed1b52005-11-21Martin Nilsson static mixed main_resolv(string sym, CompatResolver|void resolver) { mixed v = (resolver||this)->resolv(sym); if(!v)
da22f12006-06-08Martin Stjernholm  error("Could not resolve %s. "
aed1b52005-11-21Martin Nilsson  "(Perhaps the installed pike tree has been moved.)\n", sym); return v; };
97e5c72001-07-28Martin Nilsson //! This function is called when all the driver is done with all setup //! of modules, efuns, tables etc. etc. and is ready to start executing
b3926d2008-06-05Martin Stjernholm //! _real_ programs. It receives the arguments not meant for the driver. void _main(array(string) orig_argv)
ca2b071998-03-28Henrik Grubbström (Grubba) {
afa1292000-02-19Martin Nilsson  array(string) argv=copy_value(orig_argv);
5048622003-04-10Martin Nilsson  int debug,trace,run_tool;
ca2b071998-03-28Henrik Grubbström (Grubba)  object tmp;
c05dc42002-09-05Marcus Comstedt  string postparseaction=0;
ca2b071998-03-28Henrik Grubbström (Grubba) 
97f8142003-09-18Henrik Grubbström (Grubba)  predefines = initial_predefines =
7d016d2008-03-26Henrik Grubbström (Grubba)  Builtin._take_over_initial_predefines();
bfa62b1998-04-30Henrik Grubbström (Grubba)  _pike_file_name = orig_argv[0];
45c7262001-04-17Mirar (Pontus Hagland) #if constant(thread_create) _backend_thread = this_thread(); #endif
bfa62b1998-04-30Henrik Grubbström (Grubba) 
e90a8b1999-06-01Mirar (Pontus Hagland) #ifndef NOT_INSTALLED
5048622003-04-10Martin Nilsson  {
929cf72003-08-19Martin Nilsson  array parts = (getenv("PIKE_INCLUDE_PATH")||"")/PATH_SEPARATOR-({""});
5048622003-04-10Martin Nilsson  int i = sizeof(parts); while(i) add_include_path(parts[--i]);
ca2b071998-03-28Henrik Grubbström (Grubba) 
929cf72003-08-19Martin Nilsson  parts = (getenv("PIKE_PROGRAM_PATH")||"")/PATH_SEPARATOR-({""});
5048622003-04-10Martin Nilsson  i = sizeof(parts); while(i) add_program_path(parts[--i]);
ca2b071998-03-28Henrik Grubbström (Grubba) 
929cf72003-08-19Martin Nilsson  parts = (getenv("PIKE_MODULE_PATH")||"")/PATH_SEPARATOR-({""});
5048622003-04-10Martin Nilsson  i = sizeof(parts); while(i) add_module_path(parts[--i]); }
e90a8b1999-06-01Mirar (Pontus Hagland) #endif
da2ddc2002-08-11Martin Nilsson  // Some configure scripts depends on this format.
4619bd2002-07-29Martin Nilsson  string format_paths() {
25c0a82002-08-11Per Hedbor  return ("master.pike...: " + (_master_file_name || __FILE__) + "\n" "Module path...: " + pike_module_path*"\n"
020d002002-08-15Per Hedbor  " " + "\n"
25c0a82002-08-11Per Hedbor  "Include path..: " + pike_include_path*"\n"
020d002002-08-15Per Hedbor  " " + "\n"
25c0a82002-08-11Per Hedbor  "Program path..: " + pike_program_path*"\n"
020d002002-08-15Per Hedbor  " " + "\n");
4619bd2002-07-29Martin Nilsson  };
b3926d2008-06-05Martin Stjernholm  Version cur_compat_ver;
ca2b071998-03-28Henrik Grubbström (Grubba)  if(sizeof(argv)>1 && sizeof(argv[1]) && argv[1][0]=='-') {
5048622003-04-10Martin Nilsson  array q;
27a23d2003-01-27Martin Nilsson  tmp = main_resolv( "Getopt" );
8c03142002-11-15Martin Nilsson  int NO_ARG = tmp->NO_ARG; int MAY_HAVE_ARG = tmp->MAY_HAVE_ARG; int HAS_ARG = tmp->HAS_ARG;
a7a45a1998-05-11Henrik Grubbström (Grubba) 
ca2b071998-03-28Henrik Grubbström (Grubba)  q=tmp->find_all_options(argv,({
8c03142002-11-15Martin Nilsson  ({"compat_version", HAS_ARG, ({"-V", "--compat"}), 0, 0}), ({"version", NO_ARG, ({"-v", "--version"}), 0, 0}),
64ff312003-04-03Martin Nilsson  ({"dumpversion", NO_ARG, ({"--dumpversion"}), 0, 0}),
d62eab2003-09-18Martin Nilsson  ({"help", MAY_HAVE_ARG, ({"-h", "--help"}), 0, 0}),
8c03142002-11-15Martin Nilsson  ({"features", NO_ARG, ({"--features"}), 0, 0}), ({"info", NO_ARG, ({"--info"}), 0, 0}), ({"execute", HAS_ARG, ({"-e", "--execute"}), 0, 0}), ({"debug_without", HAS_ARG, ({"--debug-without"}), 0, 0}), ({"preprocess", HAS_ARG, ({"-E", "--preprocess"}), 0, 0}), ({"modpath", HAS_ARG, ({"-M", "--module-path"}), 0, 0}), ({"ipath", HAS_ARG, ({"-I", "--include-path"}), 0, 0}), ({"ppath", HAS_ARG, ({"-P", "--program-path"}), 0, 0}), ({"showpaths", NO_ARG, ({"--show-paths"}), 0, 0}), ({"warnings", NO_ARG, ({"-w", "--warnings"}), 0, 0}), ({"nowarnings", NO_ARG, ({"-W", "--woff", "--no-warnings"}), 0, 0}), ({"autoreload", NO_ARG, ({"--autoreload"}), 0, 0}), ({"master", HAS_ARG, ({"-m"}), 0, 0}), ({"compiler_trace", NO_ARG, ({"--compiler-trace"}), 0, 0}), ({"assembler_debug",MAY_HAVE_ARG, ({"--assembler-debug"}), 0, 0}), ({"optimizer_debug",MAY_HAVE_ARG, ({"--optimizer-debug"}), 0, 0}), ({"debug", MAY_HAVE_ARG, ({"--debug"}), 0, 1}), ({"trace", MAY_HAVE_ARG, ({"--trace"}), 0, 1}), ({"ignore", MAY_HAVE_ARG, ({"-Dqdatplr"}), 0, 1}), ({"ignore", HAS_ARG, ({"-s"}), 0, 0}), ({"run_tool", NO_ARG, ({"-x"}), 0, 0}),
b73de52004-11-05Martin Nilsson  ({"show_cpp_warn", NO_ARG, ({"--show-all-cpp-warnings","--picky-cpp"}), 0, 0}),
c5cc2d1998-04-29Henrik Grubbström (Grubba)  }), 1);
eba0232004-01-13Martin Nilsson 
ca2b071998-03-28Henrik Grubbström (Grubba)  /* Parse -M and -I backwards */
5048622003-04-10Martin Nilsson  for(int i=sizeof(q)-1; i>=0; i--)
ca2b071998-03-28Henrik Grubbström (Grubba)  { switch(q[i][0]) {
a20af62000-09-26Fredrik Hübinette (Hubbe)  case "compat_version": sscanf(q[i][1],"%d.%d",compat_major,compat_minor); break;
8c03142002-11-15Martin Nilsson 
bec57d1999-09-06Fredrik Hübinette (Hubbe) #ifdef PIKE_AUTORELOAD case "autoreload": autoreload_on++;
631e282003-05-28Johan Sundström  break;
bec57d1999-09-06Fredrik Hübinette (Hubbe) #endif
8c03142002-11-15Martin Nilsson 
3d14462000-09-24Per Hedbor  case "debug_without":
1a67ea2003-07-22Martin Nilsson  // FIXME: Disable loading of dumped modules?
3d14462000-09-24Per Hedbor  foreach( q[i][1]/",", string feature ) { switch( feature ) { case "ttf": no_resolv[ "_Image_TTF" ] = 1; break; case "zlib": no_resolv[ "Gz" ] = 1; break; case "unisys": no_resolv[ "_Image_GIF" ] = 1; no_resolv[ "_Image_TIFF" ] = 1; break; case "threads": // not really 100% correct, but good enough for most things. no_resolv[ "Thread" ] = 1;
f595e92003-01-01Martin Nilsson  add_constant( "thread_create" );
3d14462000-09-24Per Hedbor  break; default: no_resolv[ feature ] = 1; break; } } break;
8c03142002-11-15Martin Nilsson 
c5cc2d1998-04-29Henrik Grubbström (Grubba)  case "debug": debug+=(int)q[i][1]; break;
862fb41998-04-05Fredrik Hübinette (Hubbe) 
c5cc2d1998-04-29Henrik Grubbström (Grubba) #if constant(_compiler_trace) case "compiler_trace": _compiler_trace(1); break; #endif /* constant(_compiler_trace) */
8f45692001-01-14Henrik Grubbström (Grubba) #if constant(_assembler_debug) case "assembler_debug": _assembler_debug((int)q[i][1]); break; #endif /* constant(_assembler_debug) */
e27a5c1999-11-19Henrik Grubbström (Grubba) #if constant(_optimizer_debug) case "optimizer_debug": _optimizer_debug((int)q[i][1]); break; #endif /* constant(_optimizer_debug) */
c5cc2d1998-04-29Henrik Grubbström (Grubba)  case "trace": trace+=(int)q[i][1]; break;
862fb41998-04-05Fredrik Hübinette (Hubbe) 
ca2b071998-03-28Henrik Grubbström (Grubba)  case "modpath": add_module_path(q[i][1]); break;
eba0232004-01-13Martin Nilsson 
ca2b071998-03-28Henrik Grubbström (Grubba)  case "ipath": add_include_path(q[i][1]); break;
eba0232004-01-13Martin Nilsson 
ca2b071998-03-28Henrik Grubbström (Grubba)  case "ppath": add_program_path(q[i][1]); break;
c5cc2d1998-04-29Henrik Grubbström (Grubba)  case "warnings":
ca2b071998-03-28Henrik Grubbström (Grubba)  want_warnings++; break;
ac51841998-04-29Henrik Grubbström (Grubba) 
b714e12002-09-05Marcus Comstedt  case "nowarnings":
098c8a2000-03-30Henrik Grubbström (Grubba)  want_warnings--; break;
ac51841998-04-29Henrik Grubbström (Grubba)  case "master": _master_file_name = q[i][1]; break;
66dca02002-09-05Marcus Comstedt  case "run_tool":
c05dc42002-09-05Marcus Comstedt  run_tool = 1;
66dca02002-09-05Marcus Comstedt  break;
f6da7b2004-06-27Martin Nilsson  case "show_cpp_warn": show_if_constant_errors = 1; break;
ca2b071998-03-28Henrik Grubbström (Grubba)  } }
eba0232004-01-13Martin Nilsson 
b3926d2008-06-05Martin Stjernholm  cur_compat_ver = Version (compat_major, compat_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; } }
afa1292000-02-19Martin Nilsson  foreach(q, array opts)
ca2b071998-03-28Henrik Grubbström (Grubba)  { switch(opts[0]) {
64ff312003-04-03Martin Nilsson  case "dumpversion": write("%d.%d.%d\n", __REAL_MAJOR__, __REAL_MINOR__, __REAL_BUILD__); exit(0);
ca2b071998-03-28Henrik Grubbström (Grubba)  case "version":
de279b2008-01-04Martin Nilsson  werror(version() + " Copyright © 1994-2008 Linköping University\n"
ca2b071998-03-28Henrik Grubbström (Grubba)  "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"
b38f142002-04-30Martin Nilsson  "COPYING and COPYRIGHT in the Pike distribution for more details.\n");
ca2b071998-03-28Henrik Grubbström (Grubba)  exit(0);
eba0232004-01-13Martin Nilsson 
ca2b071998-03-28Henrik Grubbström (Grubba)  case "help":
3bc9eb2004-02-27Martin Nilsson  werror( main_resolv("Tools.MasterHelp")->do_help(opts[1]) );
ca2b071998-03-28Henrik Grubbström (Grubba)  exit(0);
eba0232004-01-13Martin Nilsson 
94c8552001-01-19Mirar (Pontus Hagland)  case "features":
a6b6df2001-01-19Mirar (Pontus Hagland)  postparseaction="features"; break; case "info": postparseaction="info";
94c8552001-01-19Mirar (Pontus Hagland)  break;
2ea8261998-05-12Martin Stjernholm  case "showpaths":
4619bd2002-07-29Martin Nilsson  werror(format_paths());
2ea8261998-05-12Martin Stjernholm  exit(0);
eba0232004-01-13Martin Nilsson 
ca2b071998-03-28Henrik Grubbström (Grubba)  case "execute":
dd75be2003-02-26Martin Stjernholm #ifdef __AUTO_BIGNUM__
3bc9eb2004-02-27Martin Nilsson  main_resolv( "Gmp.bignum" );
dd75be2003-02-26Martin Stjernholm #endif /* __AUTO_BIGNUM__ */
f9a0962003-03-20Martin Stjernholm 
3215c92003-05-15Henrik Grubbström (Grubba)  random_seed((time() ^ (getpid()<<8))); argv = tmp->get_args(argv,1);
f9a0962003-03-20Martin Stjernholm  program prog;
729acf2008-05-30Martin Stjernholm  mixed compile_err = catch {;
b3926d2008-06-05Martin Stjernholm  if(cur_compat_ver <= Version(7,4))
729acf2008-05-30Martin Stjernholm  prog = compile_string( "mixed create(int argc, array(string) argv,array(string) env){"+ opts[1]+";}"); else 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;
b3926d2008-06-05Martin Stjernholm  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 + ";}");
729acf2008-05-30Martin Stjernholm  } };
be62e62008-05-30Henrik Grubbström (Grubba)  if (compile_err) { if (compile_err->is_cpp_or_compilation_error) { // Don't clutter the output with the backtrace for // compilation errors. werror (describe_error (compile_err)); exit (20); } else throw (compile_err);
d385d72004-05-01Martin Nilsson  }
f9a0962003-03-20Martin Stjernholm  #if constant(_debug) if(debug) _debug(debug); #endif
97f8142003-09-18Henrik Grubbström (Grubba)  if(trace) trace = predef::trace(trace);
f9a0962003-03-20Martin Stjernholm  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.
b3926d2008-06-05Martin Stjernholm  if(cur_compat_ver <= Version(7,4)) prog (sizeof(argv),argv,getenv()); else if (cur_compat_ver <= Version (7, 6))
f9a0962003-03-20Martin Stjernholm  ret = prog()->run(sizeof(argv),argv,getenv());
b3926d2008-06-05Martin Stjernholm  else ret = prog()->run(sizeof(argv),argv);
f9a0962003-03-20Martin Stjernholm  };
97f8142003-09-18Henrik Grubbström (Grubba)  predef::trace(trace);
f9a0962003-03-20Martin Stjernholm  if (err) { handle_error (err); ret = 10; }
70e2ca2003-01-01Martin Nilsson  if(stringp(ret)) { write(ret); if(ret[-1]!='\n') write("\n"); }
2ac59e2002-12-29Martin Nilsson  if(!intp(ret) || ret<0) ret=0; exit(ret);
fcf7281998-04-28Fredrik Hübinette (Hubbe) 
c5cc2d1998-04-29Henrik Grubbström (Grubba)  case "preprocess":
dd75be2003-02-26Martin Stjernholm #ifdef __AUTO_BIGNUM__
3bc9eb2004-02-27Martin Nilsson  main_resolv( "Gmp.bignum" );
dd75be2003-02-26Martin Stjernholm #endif /* __AUTO_BIGNUM__ */
70e2ca2003-01-01Martin Nilsson  write(cpp(master_read_file(opts[1]),opts[1]));
c5cc2d1998-04-29Henrik Grubbström (Grubba)  exit(0);
ca2b071998-03-28Henrik Grubbström (Grubba)  } }
caa3221998-04-15Henrik Grubbström (Grubba)  argv = tmp->get_args(argv,1);
ca2b071998-03-28Henrik Grubbström (Grubba)  }
b3926d2008-06-05Martin Stjernholm  else cur_compat_ver = Version (compat_major, compat_minor);
ca2b071998-03-28Henrik Grubbström (Grubba) 
a6b6df2001-01-19Mirar (Pontus Hagland)  switch (postparseaction)
94c8552001-01-19Mirar (Pontus Hagland)  {
a6b6df2001-01-19Mirar (Pontus Hagland)  case "features":
3bc9eb2004-02-27Martin Nilsson  write( main_resolv( "Tools.Install.features" )()*"\n"+"\n" );
70e2ca2003-01-01Martin Nilsson  exit(0);
a6b6df2001-01-19Mirar (Pontus Hagland)  case "info":
70e2ca2003-01-01Martin Nilsson  write("Software......Pike\n" "Version......."+version()+"\n" "WWW...........\n" "\n" "pike binary..."+_pike_file_name+"\n"+ format_paths() + "\n" "Features......"+
3bc9eb2004-02-27Martin Nilsson  main_resolv( "Tools.Install.features" )()*"\n "+
70e2ca2003-01-01Martin Nilsson  "\n");
a6b6df2001-01-19Mirar (Pontus Hagland)  exit(0);
94c8552001-01-19Mirar (Pontus Hagland)  }
b4682a2003-02-26Martin Nilsson #ifdef __AUTO_BIGNUM__
3bc9eb2004-02-27Martin Nilsson  main_resolv( "Gmp.bignum" );
b4682a2003-02-26Martin Nilsson #endif /* __AUTO_BIGNUM__ */
1808722001-08-31Fredrik Hübinette (Hubbe)  random_seed(time() ^ (getpid()<<8));
9339fc2000-01-09Fredrik Hübinette (Hubbe) 
c05dc42002-09-05Marcus Comstedt  if(sizeof(argv)==1)
ca2b071998-03-28Henrik Grubbström (Grubba)  {
db77fa2002-12-14Martin Nilsson  if(run_tool) { werror("Pike -x specificed without tool name.\n" "Available tools:\n"); mapping t = ([]); int i;
f306b12005-04-15Henrik Grubbström (Grubba)  object ts = main_resolv("Tools.Standalone", get_compilation_handler(compat_major, compat_minor));
6e2cfd2003-10-08Martin Stjernholm  foreach (indices(ts), string s) { mixed val = ts[s]; if (programp (val)) { object o = val(); if(!o->main) continue; t[s] = o->description || ""; i = max(i, sizeof(s)); }
db77fa2002-12-14Martin Nilsson  } foreach(sort(indices(t)), string s) werror(" %-"+i+"s %s\n", s, t[s]); exit(1); }
f306b12005-04-15Henrik Grubbström (Grubba)  main_resolv("Tools.Hilfe", get_compilation_handler(compat_major, compat_minor))->StdinHilfe();
caa3221998-04-15Henrik Grubbström (Grubba)  exit(0);
ca2b071998-03-28Henrik Grubbström (Grubba)  }
4619bd2002-07-29Martin Nilsson  else argv=argv[1..];
ca2b071998-03-28Henrik Grubbström (Grubba) 
586d1c2000-09-04Fredrik Hübinette (Hubbe)  program prog;
34fb3d1998-10-31Henrik Grubbström (Grubba) 
66dca02002-09-05Marcus Comstedt  if(run_tool) { mixed err = catch {
f306b12005-04-15Henrik Grubbström (Grubba)  prog = main_resolv("Tools.Standalone." + argv[0], get_compilation_handler(compat_major, compat_minor));
66dca02002-09-05Marcus Comstedt  }; if (err)
d8674e2007-12-28Martin Nilsson  exit(1, "Pike: Failed to load tool %s:\n" "%s\n", argv[0], stringp(err[0])?err[0]:describe_backtrace(err));
66dca02002-09-05Marcus Comstedt 
57b52d2003-05-31Martin Stjernholm  argv[0] = search(programs, prog) || argv[0];
66dca02002-09-05Marcus Comstedt  } else { argv[0]=combine_path_with_cwd(argv[0]); mixed err = catch { prog=(program)argv[0]; };
f6da7b2004-06-27Martin Nilsson  if (err) {
d8674e2007-12-28Martin Nilsson  string fn = argv[0]; if( !file_stat(fn) ) { if( file_stat(fn+".pike") ) fn += ".pike"; else
9f220b2008-05-12Henrik Grubbström (Grubba)  exit(1, "Could not find file %O.\n", fn);
d8674e2007-12-28Martin Nilsson  } if( !file_stat(fn)->isreg ) exit(1, "File %O is not a regular file.\n", fn); if( !master_read_file(fn) )
9f220b2008-05-12Henrik Grubbström (Grubba)  exit(1, "File %O is not readable. %s.\n", fn, strerror(errno()));
729acf2008-05-30Martin Stjernholm  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", describe_backtrace(err));
f6da7b2004-06-27Martin Nilsson  }
39979e2004-09-06Martin Stjernholm  // 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. programs[argv[0]] = no_value;
66dca02002-09-05Marcus Comstedt  }
34fb3d1998-10-31Henrik Grubbström (Grubba) 
39979e2004-09-06Martin Stjernholm  programs["/main"] = prog;
d8674e2007-12-28Martin Nilsson  // FIXME: Can this occur at all?
586d1c2000-09-04Fredrik Hübinette (Hubbe)  if(!prog)
3bc9eb2004-02-27Martin Nilsson  error("Pike: Couldn't find script to execute\n(%O)\n", argv[0]);
ca2b071998-03-28Henrik Grubbström (Grubba) 
862fb41998-04-05Fredrik Hübinette (Hubbe) #if constant(_debug) if(debug) _debug(debug); #endif
97f8142003-09-18Henrik Grubbström (Grubba)  if(trace) trace = predef::trace(trace);
5048622003-04-10Martin Nilsson  mixed ret;
f9a0962003-03-20Martin Stjernholm  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.
41d0af2003-04-10Martin Nilsson  object script;
b3926d2008-06-05Martin Stjernholm  if(cur_compat_ver <= Version(7,4)) {
41d0af2003-04-10Martin Nilsson  script=prog(); } else { script=prog(argv); }
f9a0962003-03-20Martin Stjernholm  if(!script->main)
3bc9eb2004-02-27Martin Nilsson  error("Error: %s has no main().\n", argv[0]);
b3926d2008-06-05Martin Stjernholm  if (cur_compat_ver <= Version (7, 6)) ret=script->main(sizeof(argv),argv,getenv()); else ret=script->main(sizeof(argv),argv);
f9a0962003-03-20Martin Stjernholm  };
ead42e2004-07-04Martin Stjernholm  // Disable tracing.
b440ab2004-02-08Henrik Grubbström (Grubba)  trace = predef::trace(trace);
f9a0962003-03-20Martin Stjernholm  if (err) { handle_error (err);
5048622003-04-10Martin Nilsson  ret = 10;
f9a0962003-03-20Martin Stjernholm  }
84d89c2003-04-15Martin Nilsson  if(!intp(ret)) { werror("Error: Non-integer value %O returned from main.\n", ret); exit(10); }
5048622003-04-10Martin Nilsson  if(ret >=0) exit([int]ret);
53a32a2000-06-04Francesco Chemolli  _async=1;
eba0232004-01-13Martin Nilsson 
b440ab2004-02-08Henrik Grubbström (Grubba)  // Reenable tracing. trace = predef::trace(trace);
87f9082001-03-12Fredrik Hübinette (Hubbe)  while(1) { mixed err=catch { while(1)
677d262003-11-14Martin Stjernholm  Builtin.__backend(3600.0);
87f9082001-03-12Fredrik Hübinette (Hubbe)  }; master()->handle_error(err); }
ca2b071998-03-28Henrik Grubbström (Grubba) }
01d3c91999-11-04Henrik Grubbström (Grubba) #if constant(thread_local) object inhibit_compile_errors = thread_local(); void set_inhibit_compile_errors(mixed f) { inhibit_compile_errors->set(f); }
71d9951999-11-29Henrik Grubbström (Grubba)  mixed get_inhibit_compile_errors() {
c2eb4a1999-11-29David Hedbor  return inhibit_compile_errors->get();
71d9951999-11-29Henrik Grubbström (Grubba) }
01d3c91999-11-04Henrik Grubbström (Grubba) #else /* !constant(thread_local) */
ca2b071998-03-28Henrik Grubbström (Grubba) mixed inhibit_compile_errors; void set_inhibit_compile_errors(mixed f) { inhibit_compile_errors=f; }
71d9951999-11-29Henrik Grubbström (Grubba)  mixed get_inhibit_compile_errors() {
c2eb4a1999-11-29David Hedbor  return inhibit_compile_errors;
71d9951999-11-29Henrik Grubbström (Grubba) }
01d3c91999-11-04Henrik Grubbström (Grubba) #endif /* constant(thread_local) */
ca2b071998-03-28Henrik Grubbström (Grubba) 
0024f92001-06-06Mirar (Pontus Hagland) static private function(string:string) _trim_file_name_cb=0;
ca2b071998-03-28Henrik Grubbström (Grubba) string trim_file_name(string s) {
4839dd2001-09-02Marcus Comstedt #ifdef PIKE_MODULE_RELOC s = relocate_module(s); #endif
e37a3e1999-10-09Fredrik Hübinette (Hubbe)  if(getenv("LONG_PIKE_ERRORS")) return s;
471ed91998-04-24Fredrik Hübinette (Hubbe)  if(getenv("SHORT_PIKE_ERRORS")) return BASENAME(s);
0024f92001-06-06Mirar (Pontus Hagland)  if (_trim_file_name_cb) return _trim_file_name_cb(s);
df2c632000-08-02Henrik Grubbström (Grubba)  /* getcwd() can fail, but since this is called from handle_error(), * we don't want to fail, so we don't care about that. */ catch { string cwd=getcwd(); if (sizeof(cwd) && (cwd[-1] != '/')) { cwd += "/"; }
28351b2003-05-31Martin Stjernholm  if(has_prefix (s, cwd)) return s[sizeof(cwd)..];
df2c632000-08-02Henrik Grubbström (Grubba)  };
ca2b071998-03-28Henrik Grubbström (Grubba)  return s; }
0024f92001-06-06Mirar (Pontus Hagland) 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; }
97e5c72001-07-28Martin Nilsson 
677d262003-11-14Martin Stjernholm //! 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.
ca2b071998-03-28Henrik Grubbström (Grubba) void compile_error(string file,int line,string err) {
01d3c91999-11-04Henrik Grubbström (Grubba)  mixed val;
3112422000-03-27Per Hedbor  if(! (val = get_inhibit_compile_errors() ))
ca2b071998-03-28Henrik Grubbström (Grubba)  {
2f520e2002-04-28Martin Nilsson  werror( "%s:%s:%s\n",trim_file_name(file), line?(string)line:"-",err );
ca2b071998-03-28Henrik Grubbström (Grubba)  }
01d3c91999-11-04Henrik Grubbström (Grubba)  else if(objectp(val) || programp(val) || functionp(val))
ca2b071998-03-28Henrik Grubbström (Grubba)  {
01d3c91999-11-04Henrik Grubbström (Grubba)  if (objectp(val) && val->compile_error) { val->compile_error(file, line, err);
71f4fe2008-05-01Martin Nilsson  } else if (callablep(val)) {
3112422000-03-27Per Hedbor  val(file, line, err);
01d3c91999-11-04Henrik Grubbström (Grubba)  }
ca2b071998-03-28Henrik Grubbström (Grubba)  } }
97e5c72001-07-28Martin Nilsson 
677d262003-11-14Martin Stjernholm //! 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.
ca2b071998-03-28Henrik Grubbström (Grubba) void compile_warning(string file,int line,string err) {
01d3c91999-11-04Henrik Grubbström (Grubba)  mixed val;
3112422000-03-27Per Hedbor  if(!(val = get_inhibit_compile_errors() ))
ca2b071998-03-28Henrik Grubbström (Grubba)  { if(want_warnings)
2f520e2002-04-28Martin Nilsson  werror( "%s:%s: Warning: %s\n",trim_file_name(file), line?(string)line:"-",err ); } else if (objectp(val) && val->compile_warning) {
23184f2003-04-30Martin Nilsson  ([function(string,int,string:void)]([object]val) ->compile_warning)(file, line, err);
ca2b071998-03-28Henrik Grubbström (Grubba)  } }
97e5c72001-07-28Martin Nilsson 
8594c82001-08-15Martin Stjernholm //! This function is called when an exception is catched during //! compilation. Its message is also reported to @[compile_error] if //! this function returns zero. int compile_exception (array|object trace) {
729acf2008-05-30Martin Stjernholm  if (objectp (trace) && ([object]trace)->is_cpp_or_compilation_error) // Errors thrown by cpp(), compile() or a compile callback should // be reported as a normal compile error, so let the caller do // just that.
677d262003-11-14Martin Stjernholm  return 0;
8594c82001-08-15Martin Stjernholm  if (mixed val = get_inhibit_compile_errors()) {
23184f2003-04-30Martin Nilsson  if (objectp(val) && ([object]val)->compile_exception) return ([function(object:int)]([object]val) ->compile_exception)([object]trace);
8594c82001-08-15Martin Stjernholm  } else { handle_error (trace); return 1; } return 0; }
97e5c72001-07-28Martin Nilsson //! 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.
8f23062000-06-09Martin Stjernholm 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.
3c6f582002-05-24Martin Stjernholm #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.
8f23062000-06-09Martin Stjernholm  werror ("GC warning: Garbing cycle where destroy() will be called " "in arbitrary order:\n%{ %s\n%}",
d3a3322002-11-23Marcus Comstedt  sprintf("%O", args[0][*]));
3c6f582002-05-24Martin Stjernholm #endif
8f23062000-06-09Martin Stjernholm  break; default: werror ("%s warning: %s %O\n", capitalize (where), what, args); } }
ca2b071998-03-28Henrik Grubbström (Grubba) 
bd8e1a2006-01-19Henrik Grubbström (Grubba) static object Charset;
97e5c72001-07-28Martin Nilsson  //! This function is called by cpp() when it wants to do //! character code conversion.
f4f08d1999-02-26Henrik Grubbström (Grubba) string decode_charset(string data, string charset) {
bd8e1a2006-01-19Henrik Grubbström (Grubba)  if (!Charset) {
23184f2003-04-30Martin Nilsson  object mod = [object]resolv("Locale");
f4f08d1999-02-26Henrik Grubbström (Grubba) 
bd8e1a2006-01-19Henrik Grubbström (Grubba)  Charset = [object](mod && mod["Charset"]); if (!Charset) compile_cb_error("Cannot handle charset - no Locale.Charset module found.");
f4f08d1999-02-26Henrik Grubbström (Grubba)  }
677d262003-11-14Martin Stjernholm  if (mixed err = catch {
bd8e1a2006-01-19Henrik Grubbström (Grubba)  object decoder = ([function(string:object)]Charset.decoder)(charset);
677d262003-11-14Martin Stjernholm  return ([function(void:string)]([function(string:object)]decoder-> feed)(data)->drain)(); }) compile_cb_rethrow (err);
f4f08d1999-02-26Henrik Grubbström (Grubba) }
da0a822000-08-29Martin Stjernholm class Describer
ca2b071998-03-28Henrik Grubbström (Grubba) {
da0a822000-08-29Martin Stjernholm  int clipped=0; int canclip=0; mapping(mixed:int|string) ident = ([]); int identcount = 0; void identify_parts (mixed stuff) {
9f71092000-11-20Martin Stjernholm  // Use an array as stack here instead of recursing directly; we // might be pressed for stack space if the backtrace being // described is a stack overflow. array identify_stack = ({stuff}); while (sizeof (identify_stack)) { stuff = identify_stack[-1];
35320b2004-10-30Martin Stjernholm  identify_stack = identify_stack[..<1];
54f7af2006-12-07Henrik Grubbström (Grubba)  if (!intp(ident[stuff])) continue; // Already identified.
26ece22001-06-18Henrik Grubbström (Grubba)  if (objectp (stuff) || functionp (stuff) || programp (stuff)) ident[stuff]++; else if (arrayp (stuff)) {
9f71092000-11-20Martin Stjernholm  if (!ident[stuff]++) identify_stack += stuff; } else if (multisetp (stuff)) { if (!ident[stuff]++)
23184f2003-04-30Martin Nilsson  identify_stack += indices([multiset]stuff);
9f71092000-11-20Martin Stjernholm  } else if (mappingp (stuff)) { if (!ident[stuff]++)
23184f2003-04-30Martin Nilsson  identify_stack += indices([mapping]stuff) + values([mapping]stuff);
9f71092000-11-20Martin Stjernholm  }
da0a822000-08-29Martin Stjernholm  } }
2602b82000-08-29Martin Stjernholm  string describe_string (string m, int maxlen) { canclip++; if(sizeof(m) < maxlen) { string t = sprintf("%O", m);
eba0232004-01-13Martin Nilsson  if (sizeof(t) < (maxlen + 2))
2602b82000-08-29Martin Stjernholm  return t; t = 0; } clipped++; if(maxlen>10) return sprintf("%O+[%d]",m[..maxlen-5],sizeof(m)-(maxlen-5));
eba0232004-01-13Martin Nilsson  return "string["+sizeof(m)+"]";
2602b82000-08-29Martin Stjernholm  } string describe_array (array m, int maxlen) { if(!sizeof(m)) return "({})"; else { if(maxlen<5) { clipped++; return "array["+sizeof(m)+"]"; } else { canclip++; return "({" + describe_comma_list(m,maxlen-2) +"})"; } } } string describe_mapping (mapping m, int maxlen) { if(!sizeof(m)) return "([])"; else return "mapping["+sizeof(m)+"]"; } string describe_multiset (multiset m, int maxlen) { if(!sizeof(m)) return "(<>)"; else return "multiset["+sizeof(m)+"]"; }
da0a822000-08-29Martin Stjernholm  string describe (mixed m, int maxlen)
ca2b071998-03-28Henrik Grubbström (Grubba)  {
e617062004-01-08Martin Nilsson  catch { if (stringp (ident[m])) return [string]ident[m]; else if (intp (ident[m]) && ident[m] > 1) ident[m] = "@" + identcount++; };
da0a822000-08-29Martin Stjernholm 
0a064e2002-11-24Henrik Grubbström (Grubba)  string res; if (catch (res=sprintf("%t",m))) res = "object"; // Object with a broken _sprintf(), probably. switch(res) { case "int":
08ca0a2004-12-08Martin Stjernholm  if (!m && zero_type (m) == 1) return "UNDEFINED";
0a064e2002-11-24Henrik Grubbström (Grubba)  case "float": return (string)m; case "string":
23184f2003-04-30Martin Nilsson  return describe_string ([string]m, maxlen);
0a064e2002-11-24Henrik Grubbström (Grubba)  case "array":
23184f2003-04-30Martin Nilsson  res = describe_array ([array]m, maxlen);
0a064e2002-11-24Henrik Grubbström (Grubba)  break; case "mapping":
23184f2003-04-30Martin Nilsson  res = describe_mapping ([mapping]m, maxlen);
0a064e2002-11-24Henrik Grubbström (Grubba)  break; case "multiset":
23184f2003-04-30Martin Nilsson  res = describe_multiset ([multiset]m, maxlen);
0a064e2002-11-24Henrik Grubbström (Grubba)  break; case "function":
23184f2003-04-30Martin Nilsson  if (string tmp=describe_function([function]m)) res = tmp;
0a064e2002-11-24Henrik Grubbström (Grubba)  break; case "program":
23184f2003-04-30Martin Nilsson  if(string tmp=describe_program([program]m)) res = tmp;
0a064e2002-11-24Henrik Grubbström (Grubba)  break; default: /* object or type. */ if (catch { if(string tmp=sprintf("%O", m)) res = tmp; }) { // Extra paranoia case. res = sprintf("Instance of %O", _typeof(m));
f645f02001-10-26Henrik Grubbström (Grubba)  }
0a064e2002-11-24Henrik Grubbström (Grubba)  break;
da0a822000-08-29Martin Stjernholm  }
0a064e2002-11-24Henrik Grubbström (Grubba)  if (stringp(ident[m]))
da0a822000-08-29Martin Stjernholm  return ident[m] + "=" + res; return res; }
e8ebc01999-08-27Fredrik Hübinette (Hubbe) 
da0a822000-08-29Martin Stjernholm  string describe_comma_list(array x, int maxlen) { string ret="";
e8ebc01999-08-27Fredrik Hübinette (Hubbe) 
da0a822000-08-29Martin Stjernholm  if(!sizeof(x)) return ""; if(maxlen<0) return ",,,"+sizeof(x);
5e09161999-10-15Fredrik Hübinette (Hubbe) 
da0a822000-08-29Martin Stjernholm  int clip=min(maxlen/2,sizeof(x)); int len=maxlen; int done=0;
ba20b11999-10-15Fredrik Hübinette (Hubbe)  while(1) {
da0a822000-08-29Martin Stjernholm  array(string) z=allocate(clip); array(int) isclipped=allocate(clip); array(int) clippable=allocate(clip); for(int e=0;e<clip;e++)
ba20b11999-10-15Fredrik Hübinette (Hubbe)  {
da0a822000-08-29Martin Stjernholm  clipped=0; canclip=0; z[e]=describe(x[e],len); isclipped[e]=clipped; clippable[e]=canclip;
ba20b11999-10-15Fredrik Hübinette (Hubbe)  } while(1) {
da0a822000-08-29Martin Stjernholm  string ret = z[..clip-1]*","; if(done || sizeof(ret)<=maxlen+1) { int tmp=sizeof(x)-clip-1; clipped=`+(0,@isclipped); if(tmp>=0) { clipped++; ret+=",,,"+tmp; } canclip++; return ret; } int last_newlen=len; int newlen; int clipsuggest; while(1) { int smallsize=0; int num_large=0; clipsuggest=0;
ba20b11999-10-15Fredrik Hübinette (Hubbe) 
da0a822000-08-29Martin Stjernholm  for(int e=0;e<clip;e++)
ba20b11999-10-15Fredrik Hübinette (Hubbe)  {
5e09161999-10-15Fredrik Hübinette (Hubbe)  if((sizeof(z[e])>=last_newlen || isclipped[e]) && clippable[e])
ba20b11999-10-15Fredrik Hübinette (Hubbe)  num_large++; else smallsize+=sizeof(z[e]); if(num_large * 15 + smallsize < maxlen) clipsuggest=e+1; }
eba0232004-01-13Martin Nilsson 
da0a822000-08-29Martin Stjernholm  newlen=num_large ? (maxlen-smallsize)/num_large : 0;
eba0232004-01-13Martin Nilsson 
da0a822000-08-29Martin Stjernholm  if(newlen<8 || newlen >= last_newlen) break; last_newlen=newlen; }
e8ebc01999-08-27Fredrik Hübinette (Hubbe) 
da0a822000-08-29Martin Stjernholm  if(newlen < 8 && clip) { clip-= (clip/4) || 1; if(clip > clipsuggest) clip=clipsuggest; }else{ len=newlen; done++; break; }
ba20b11999-10-15Fredrik Hübinette (Hubbe)  } }
da0a822000-08-29Martin Stjernholm  return ret; }
e8ebc01999-08-27Fredrik Hübinette (Hubbe) }
be242d2002-11-23Henrik Grubbström (Grubba) 
28351b2003-05-31Martin Stjernholm string program_path_to_name ( string path,
4ce9832003-06-05Martin Stjernholm  void|string module_prefix, void|string module_suffix, void|string object_suffix )
28351b2003-05-31Martin Stjernholm //! Converts a module path on the form @expr{"Foo.pmod/Bar.pmod"@} or //! @expr{"/path/to/pike/lib/modules/Foo.pmod/Bar.pmod"@} to a module //! identifier on the form @expr{"Foo.Bar"@}. //! //! If @[module_prefix] or @[module_suffix] are given, they are //! prepended and appended, respectively, to the returned string if //! it's a module file (i.e. ends with @expr{".pmod"@} or //! @expr{".so"@}). If @[object_suffix] is given, it's appended to the //! returned string if it's an object file (i.e. ends with //! @expr{".pike"@}).
d3a3322002-11-23Marcus Comstedt {
e3383c2006-01-25Henrik Grubbström (Grubba)  if (path == "/master") return "master" + (object_suffix || "");
d3a3322002-11-23Marcus Comstedt  array(string) sort_paths_by_length(array(string) paths) { sort(map(paths, sizeof), paths); return reverse(paths); };
28351b2003-05-31Martin Stjernholm 
e3383c2006-01-25Henrik Grubbström (Grubba)  string prefix = ""; array(Version) versions = reverse(sort(indices(compat_handler_cache))); find_prefix: foreach(versions, Version version) { CompatResolver r = compat_handler_cache[version]; if (!r) continue; // Protection against the gc... foreach(sort_paths_by_length(map(r->pike_module_path - ({""}), lambda(string s) { if (s[-1] == '/') return s; return s+"/"; })), string path_prefix) { if (has_prefix(path, path_prefix)) { path = path[sizeof(path_prefix)..]; if (version != currentversion) { prefix = ((string)version) + "::"; } break find_prefix; }
d3a3322002-11-23Marcus Comstedt  } }
28351b2003-05-31Martin Stjernholm  #if 0 // This seems broken. Why should the current directory or the // setting of SHORT_PIKE_ERRORS etc affect the module identifiers? // /mast path = trim_file_name(path); #endif string modname = replace(path, ".pmod/", "."); if(search(modname, "/")<0) path=modname;
e3383c2006-01-25Henrik Grubbström (Grubba)  path = prefix + path;
28351b2003-05-31Martin Stjernholm  if (has_suffix(path, ".module.pmod")) {
35320b2004-10-30Martin Stjernholm  return (module_prefix || "") + path[..<12] + (module_suffix || "");
28351b2003-05-31Martin Stjernholm  } if (has_suffix(path, ".pmod")) {
35320b2004-10-30Martin Stjernholm  return (module_prefix || "") + path[..<5] + (module_suffix || "");
28351b2003-05-31Martin Stjernholm  } if (has_suffix(path, ".so")) {
35320b2004-10-30Martin Stjernholm  return (module_prefix || "") + path[..<3] + (module_suffix || "");
28351b2003-05-31Martin Stjernholm  } if (has_suffix(path, ".pike")) {
35320b2004-10-30Martin Stjernholm  return path[..<5] + (object_suffix || "");
28351b2003-05-31Martin Stjernholm  } return path + (object_suffix || "");
d3a3322002-11-23Marcus Comstedt }
be242d2002-11-23Henrik Grubbström (Grubba) //! Describe the path to the module @[mod]. //! //! @param mod //! If @[mod] is a program, attempt to describe the path //! to a clone of @[mod]. //! //! @param ret_obj //! If an instance of @[mod] is found, it will be returned
e5ef062003-04-01Martin Nilsson //! by changing element @expr{0@} of @[ret_obj].
be242d2002-11-23Henrik Grubbström (Grubba) //! //! @returns //! The a description of the path. //! //! @note //! The returned description will end with a proper indexing method
e5ef062003-04-01Martin Nilsson //! currently either @expr{"."@} or @expr{"->"@}.
be242d2002-11-23Henrik Grubbström (Grubba) string describe_module(object|program mod, array(object)|void ret_obj) {
2d01ff2003-09-09Martin Stjernholm  // Note: mod might be a bignum object; objectp won't work right for // our purposes. object_program returns zero for non-objects, so we // use it instead. program parent_fun = object_program(mod); if (parent_fun) { if (ret_obj) ret_obj[0] = mod; } else if (programp (mod)) { parent_fun = mod;
aedfbc2004-01-12Martin Nilsson  // When running with debug we might be called before __INIT, so
a30b1a2004-01-12Martin Nilsson  // we have to check if objects exists before we use it.
aedfbc2004-01-12Martin Nilsson  if (objects && objectp (mod = objects[parent_fun]) && ret_obj) ret_obj[0] = mod;
be242d2002-11-23Henrik Grubbström (Grubba)  }
2d01ff2003-09-09Martin Stjernholm  else return ""; // efun
be242d2002-11-23Henrik Grubbström (Grubba)  if (mod) { catch { string res = sprintf("%O", mod);
d3a3322002-11-23Marcus Comstedt  if (res != "object" && res != "")
401fa02002-12-02Martin Stjernholm  return (objectp (objects[parent_fun]) && programs["/master"] != parent_fun?
a632422002-11-23Marcus Comstedt  res+".":res+"->");
be242d2002-11-23Henrik Grubbström (Grubba)  };
83da8e2008-05-14Henrik Grubbström (Grubba)  string res = search(all_constants(), mod); if (res) return res;
be242d2002-11-23Henrik Grubbström (Grubba)  } if (!object_program(parent_fun)) { // We might be a top-level entity.
28351b2003-05-31Martin Stjernholm  if (string path = programs_reverse_lookup (parent_fun)) return program_path_to_name(path, "", ".", "()->");
be242d2002-11-23Henrik Grubbström (Grubba)  } // Begin by describing our parent. array(object) parent_obj = ({ 0 }); string res = describe_module(function_object(parent_fun)||
c3b5642003-01-09Henrik Grubbström (Grubba)  function_program(parent_fun)||
be242d2002-11-23Henrik Grubbström (Grubba)  object_program(parent_fun), parent_obj); // werror("So far: %O parent_obj:%O\n", res, parent_obj);
401fa02002-12-02Martin Stjernholm  object|program parent =
2d01ff2003-09-09Martin Stjernholm  object_program (parent_obj[0]) ? parent_obj[0] : object_program(parent_fun); if (mod && (object_program (parent) || parent)) {
be242d2002-11-23Henrik Grubbström (Grubba)  // Object identified. catch { // Check if we're an object in parent. int i = search(values(parent), mod); if (i >= 0) {
23184f2003-04-30Martin Nilsson  return res + [string]indices(parent)[i] + ".";
be242d2002-11-23Henrik Grubbström (Grubba)  } }; } // We're cloned from something in parent. if (string fun_name = function_name(parent_fun)) { return res + fun_name + "()->"; } // No such luck. // Try identifying a clone of ourselves.
2d01ff2003-09-09Martin Stjernholm  if (!mod && (object_program (parent) || parent)) {
be242d2002-11-23Henrik Grubbström (Grubba)  catch { // Check if there's a clone of parent_fun in parent_obj. int i; array(mixed) val = values(parent);
23184f2003-04-30Martin Nilsson  array(string) ind = [array(string)]indices(parent);
be242d2002-11-23Henrik Grubbström (Grubba)  for (i=0; i < sizeof(val); i++) {
2d01ff2003-09-09Martin Stjernholm  if (object_program(val[i]) && object_program(val[i]) == parent_fun) {
be242d2002-11-23Henrik Grubbström (Grubba)  return res + ind[i] + "."; } } }; } // We're really out of luck here...
d3a3322002-11-23Marcus Comstedt  return res + (describe_program(parent_fun)||"unknown_program") + "()->";
be242d2002-11-23Henrik Grubbström (Grubba) }
97e5c72001-07-28Martin Nilsson //!
dd75be2003-02-26Martin Stjernholm string describe_object(object o)
bec57d1999-09-06Fredrik Hübinette (Hubbe) { string s;
90b03d2003-01-16Martin Stjernholm  if(zero_type (o)) return 0; // Destructed.
be242d2002-11-23Henrik Grubbström (Grubba) 
83da8e2008-05-14Henrik Grubbström (Grubba)  // Handled by the search of all_constants() below. // if (o == _static_modules) return "_static_modules";
42825a2003-05-07Martin Stjernholm  program|function(mixed...:void|object) parent_fun = object_program(o);
be242d2002-11-23Henrik Grubbström (Grubba)  /* Constant object? */ catch {
c3b5642003-01-09Henrik Grubbström (Grubba)  object|program parent_obj = (function_object(parent_fun) || function_program(parent_fun));
be242d2002-11-23Henrik Grubbström (Grubba) 
10ab772002-12-04Marcus Comstedt  if (objectp (parent_obj) || parent_obj) {
be242d2002-11-23Henrik Grubbström (Grubba)  /* Check if we have a constant object. */ object tmp = objects[parent_obj];
401fa02002-12-02Martin Stjernholm  if (objectp (tmp)) parent_obj = tmp;
be242d2002-11-23Henrik Grubbström (Grubba)  /* Try finding ourselves in parent_obj. */
b38cb32003-09-09Martin Stjernholm  int i = search(values(parent_obj), o);
be242d2002-11-23Henrik Grubbström (Grubba)  if (i >= 0) {
23184f2003-04-30Martin Nilsson  s = [string]indices(parent_obj)[i];
d3a3322002-11-23Marcus Comstedt  return describe_module(parent_obj) + s;
be242d2002-11-23Henrik Grubbström (Grubba)  } } };
83da8e2008-05-14Henrik Grubbström (Grubba)  if ((s = search(all_constants(), o))) return s;
2eb10b2004-06-13Henrik Grubbström (Grubba)  // When running with RESOLV_DEBUG this function may // get called before objects has been initialized. if(objects && objectp (objects[parent_fun]))
28351b2003-05-31Martin Stjernholm  if ((s = programs_reverse_lookup (parent_fun)) && (s=program_path_to_name(s, "", "", "()")))
a632422002-11-23Marcus Comstedt  return s;
be242d2002-11-23Henrik Grubbström (Grubba)  /* Try identifying the program. */ if(( s=describe_program(parent_fun) ))
a632422002-11-23Marcus Comstedt  return s+"()";
be242d2002-11-23Henrik Grubbström (Grubba) 
bec57d1999-09-06Fredrik Hübinette (Hubbe)  return 0; }
97e5c72001-07-28Martin Nilsson //!
23184f2003-04-30Martin Nilsson string describe_program(program|function p)
62e87b1998-04-14Fredrik Hübinette (Hubbe) { string s; if(!p) return 0;
d3a3322002-11-23Marcus Comstedt 
42825a2003-05-07Martin Stjernholm  if (p == object_program (_static_modules)) return "object_program(_static_modules)";
23184f2003-04-30Martin Nilsson  if(programp(p) &&
28351b2003-05-31Martin Stjernholm  (s = programs_reverse_lookup ([program] p)) && (s=program_path_to_name(s, "object_program(", ")", "")))
d3a3322002-11-23Marcus Comstedt  return s;
62e87b1998-04-14Fredrik Hübinette (Hubbe) 
23184f2003-04-30Martin Nilsson  if(object|program tmp=(function_object(p) || function_program(p))) {
10ab772002-12-04Marcus Comstedt  if(s = function_name(p))
c84bd12003-01-13Henrik Grubbström (Grubba)  { return describe_module(tmp) + s; } }
e8ce5e2001-04-09Fredrik Hübinette (Hubbe) 
7d016d2008-03-26Henrik Grubbström (Grubba)  if(s=Builtin.program_defined(p))
15af9c2003-12-19Marcus Comstedt  return BASENAME(s);
bec57d1999-09-06Fredrik Hübinette (Hubbe) 
83da8e2008-05-14Henrik Grubbström (Grubba)  return search(all_constants(), p);
62e87b1998-04-14Fredrik Hübinette (Hubbe) }
97e5c72001-07-28Martin Nilsson //!
2602b82000-08-29Martin Stjernholm string describe_function (function f) { if (!f) return 0; string name;
83da8e2008-05-14Henrik Grubbström (Grubba)  if (name = search(all_constants(), f)) return name;
57b52d2003-05-31Martin Stjernholm  if(string s = programs_reverse_lookup (f))
2602b82000-08-29Martin Stjernholm  {
01f0272001-11-19Martin Nilsson  if(has_suffix(s, ".pmod"))
35320b2004-10-30Martin Stjernholm  name = BASENAME(s[..<5]);
2602b82000-08-29Martin Stjernholm  else name = trim_file_name(s); }
83da8e2008-05-14Henrik Grubbström (Grubba)  else
2602b82000-08-29Martin Stjernholm  if (catch (name = function_name (f))) name = "function";
23184f2003-04-30Martin Nilsson  object o = function_object([function(mixed...:void|mixed)]f);
2d01ff2003-09-09Martin Stjernholm  if(object_program (o)) { // Check if it's an object in a way that // (hopefully) doesn't call any functions // in it (neither `== nor `!).
2602b82000-08-29Martin Stjernholm  string s; if (!catch (s = sprintf("%O",o)) && s != "object") return s+"->"+name; } return name; }
ca2b071998-03-28Henrik Grubbström (Grubba) /* 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. */
8f45692001-01-14Henrik Grubbström (Grubba) 
b07e962001-07-27Martin Nilsson //! @appears describe_backtrace
677d262003-11-14Martin Stjernholm //! Return a readable message that describes where the backtrace //! @[trace] was made (by @[backtrace]).
8f45692001-01-14Henrik Grubbström (Grubba) //!
677d262003-11-14Martin Stjernholm //! 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.
8f45692001-01-14Henrik Grubbström (Grubba) //! //! @seealso //! @[backtrace()], @[describe_error()], @[catch()], @[throw()] //!
1092512005-01-26Martin Stjernholm string describe_backtrace(mixed trace, void|int linewidth)
ca2b071998-03-28Henrik Grubbström (Grubba) { int e;
677d262003-11-14Martin Stjernholm  string ret;
d4fd0a1999-12-06Henrik Grubbström (Grubba)  int backtrace_len=((int)getenv("PIKE_BACKTRACE_LEN")) || bt_max_string_len;
ca2b071998-03-28Henrik Grubbström (Grubba) 
ba20b11999-10-15Fredrik Hübinette (Hubbe)  if(!linewidth) { linewidth=99999; catch {
677d262003-11-14Martin Stjernholm  linewidth=[int]Files()->_stdin->tcgetattr()->columns;
ba20b11999-10-15Fredrik Hübinette (Hubbe)  };
fe8fb32000-01-15Fredrik Hübinette (Hubbe)  if(linewidth<10) linewidth=99999;
ba20b11999-10-15Fredrik Hübinette (Hubbe)  }
677d262003-11-14Martin Stjernholm  // 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))); } 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);
a232721999-10-06Henrik Grubbström (Grubba)  }
661c642004-03-15Martin Stjernholm  else ret = "";
677d262003-11-14Martin Stjernholm  }
be62e62008-05-30Henrik Grubbström (Grubba)  else {
78db9a2008-05-31Martin Nilsson #if constant(_gdb_breakpoint)
be62e62008-05-30Henrik Grubbström (Grubba)  _gdb_breakpoint();
78db9a2008-05-31Martin Nilsson #endif
be62e62008-05-30Henrik Grubbström (Grubba)  return sprintf ("<Invalid backtrace/error container: %O>\n" "%s\n", trace, describe_backtrace(backtrace())); }
ca2b071998-03-28Henrik Grubbström (Grubba)  {
da0a822000-08-29Martin Stjernholm  Describer desc = Describer();
23184f2003-04-30Martin Nilsson  array trace = [array]trace;
da0a822000-08-29Martin Stjernholm 
9f71092000-11-20Martin Stjernholm  int end = 0; if( (sizeof(trace)>1) && arrayp(trace[0]) &&
23184f2003-04-30Martin Nilsson  (sizeof([array]trace[0]) > 2) && (([array]trace[0])[2] == _main))
9f71092000-11-20Martin Stjernholm  end = 1;
aed1b52005-11-21Martin Nilsson  if( end==1 && (sizeof(trace)>2) && arrayp(trace[1]) && (sizeof([array]trace[1])>2) && (([array]trace[1])[2] == main_resolv) && arrayp(trace[-1]) && (sizeof([array]trace[-1])>2) && (([array]trace[-1]))[2] == compile_string ) end = sizeof(trace);
9f71092000-11-20Martin Stjernholm  mapping(string:int) prev_pos = ([]); array(string) frames = ({}); int loop_start = 0, loop_next, loops; for(e = sizeof(trace)-1; e>=end; e--)
ca2b071998-03-28Henrik Grubbström (Grubba)  { mixed tmp; string row;
513cbc2003-01-27Martin Nilsson  if (array err=[array]catch {
23184f2003-04-30Martin Nilsson  tmp = trace[e];
a232721999-10-06Henrik Grubbström (Grubba)  if(stringp(tmp))
ca2b071998-03-28Henrik Grubbström (Grubba)  {
855b722003-04-29Martin Nilsson  row=[string]tmp;
ca2b071998-03-28Henrik Grubbström (Grubba)  }
a232721999-10-06Henrik Grubbström (Grubba)  else if(arrayp(tmp))
ca2b071998-03-28Henrik Grubbström (Grubba)  {
d4855b2004-01-13Martin Nilsson  if(sprintf("%t",tmp)=="object") {
1375d22004-01-13Martin Nilsson  // tmp is backtrace_frame desc->identify_parts( tmp->args ); } else desc->identify_parts( tmp );
855b722003-04-29Martin Nilsson  array tmp = [array]tmp;
ba20b11999-10-15Fredrik Hübinette (Hubbe)  string pos;
dbe79a1999-12-07Henrik Grubbström (Grubba)  if(sizeof(tmp)>=2 && stringp(tmp[0])) { if (intp(tmp[1])) {
855b722003-04-29Martin Nilsson  pos=trim_file_name([string]tmp[0])+":"+(string)tmp[1];
dbe79a1999-12-07Henrik Grubbström (Grubba)  } else {
855b722003-04-29Martin Nilsson  pos = sprintf("%s:Bad line %t", trim_file_name([string]tmp[0]), tmp[1]);
dbe79a1999-12-07Henrik Grubbström (Grubba)  }
a232721999-10-06Henrik Grubbström (Grubba)  }else{
855b722003-04-29Martin Nilsson  string desc="Unknown program";
a232721999-10-06Henrik Grubbström (Grubba)  if(sizeof(tmp)>=3 && functionp(tmp[2])) {
e118831999-12-22Per Hedbor  catch {
23184f2003-04-30Martin Nilsson  if(mixed tmp=function_object([function(mixed...: void|mixed)]tmp[2]))
a232721999-10-06Henrik Grubbström (Grubba)  if(tmp=object_program(tmp))
855b722003-04-29Martin Nilsson  if(tmp=describe_program([program]tmp)) desc=[string]tmp;
a232721999-10-06Henrik Grubbström (Grubba)  }; }
ba20b11999-10-15Fredrik Hübinette (Hubbe)  pos=desc; }
9f71092000-11-20Martin Stjernholm 
ba20b11999-10-15Fredrik Hübinette (Hubbe)  string data;
eba0232004-01-13Martin Nilsson 
ba20b11999-10-15Fredrik Hübinette (Hubbe)  if(sizeof(tmp)>=3) {
dfca1f2000-08-22Martin Stjernholm  if(functionp(tmp[2])) {
855b722003-04-29Martin Nilsson  data = describe_function ([function]tmp[2]);
dfca1f2000-08-22Martin Stjernholm  }
ba20b11999-10-15Fredrik Hübinette (Hubbe)  else if (stringp(tmp[2])) {
855b722003-04-29Martin Nilsson  data = [string]tmp[2];
ba20b11999-10-15Fredrik Hübinette (Hubbe)  } else data ="unknown function";
eba0232004-01-13Martin Nilsson 
ba20b11999-10-15Fredrik Hübinette (Hubbe)  data+="("+
da0a822000-08-29Martin Stjernholm  desc->describe_comma_list(tmp[3..], backtrace_len)+
ba20b11999-10-15Fredrik Hübinette (Hubbe)  ")"; if(sizeof(pos)+sizeof(data) < linewidth-4) { row=sprintf("%s: %s",pos,data); }else{ row=sprintf("%s:\n%s",pos,sprintf(" %*-/s",linewidth-6,data)); }
dbe79a1999-12-07Henrik Grubbström (Grubba)  } else { row = pos;
62e87b1998-04-14Fredrik Hübinette (Hubbe)  }
ca2b071998-03-28Henrik Grubbström (Grubba)  }
a232721999-10-06Henrik Grubbström (Grubba)  else {
9798481999-12-06Henrik Grubbström (Grubba)  if (tmp) {
e0e05f2000-03-23Martin Stjernholm  if (catch (row = sprintf("%O", tmp))) row = describe_program(object_program(tmp)) + " with broken _sprintf()";
9798481999-12-06Henrik Grubbström (Grubba)  } else { row = "Destructed object"; }
a232721999-10-06Henrik Grubbström (Grubba)  }
6e343b2001-03-14Martin Stjernholm  }) { row = sprintf("Error indexing backtrace line %d: %s (%O)!", e, err[0], err[1]); }
5d6a562001-11-08Fredrik Hübinette (Hubbe)  int dup_frame; if (!zero_type(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++) { loops += new_loop; continue; } } } prev_pos[row] = sizeof(frames); if (loop_start) { array(string) tail; if (!loop_next) tail = ({}), loops++; else tail = frames[loop_start + sizeof(frames) .. loop_next - 1 + sizeof(frames)]; if (loops) frames += ({sprintf ("... last %d frames above repeated %d times ...\n", -loop_start, loops)}); frames += tail; prev_pos = ([]); loop_start = 0; }
9f71092000-11-20Martin Stjernholm  frames += ({row + "\n"}); } if (loop_start) { // Want tail to contain a full loop rather than being empty; it // looks odd when the repeat message ends the backtrace.
5d6a562001-11-08Fredrik Hübinette (Hubbe)  array(string) tail = frames[loop_start + sizeof(frames) .. loop_next - 1 + sizeof(frames)];
d48c1f2001-12-18Martin Stjernholm  if (loops) frames += ({sprintf("... last %d frames above repeated %d times ...\n", -loop_start, loops)});
9f71092000-11-20Martin Stjernholm  frames += tail;
ca2b071998-03-28Henrik Grubbström (Grubba)  }
9f71092000-11-20Martin Stjernholm  ret += frames * "";
ca2b071998-03-28Henrik Grubbström (Grubba)  }
5be4aa2001-11-12Martin Stjernholm  return ret;
ca2b071998-03-28Henrik Grubbström (Grubba) }
471ed91998-04-24Fredrik Hübinette (Hubbe) 
b07e962001-07-27Martin Nilsson //! @appears describe_error
8f45692001-01-14Henrik Grubbström (Grubba) //!
677d262003-11-14Martin Stjernholm //! Return the error message from an error object or array (typically
0fcf0c2004-03-05Martin Nilsson //! caught by a @[catch]). The type of the error is checked, hence //! @[err] is declared as @expr{mixed@} and not @expr{object|array@}.
677d262003-11-14Martin Stjernholm //! //! 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.
8f45692001-01-14Henrik Grubbström (Grubba) //! //! @seealso
677d262003-11-14Martin Stjernholm //! @[describe_backtrace()], @[get_backtrace]
8f45692001-01-14Henrik Grubbström (Grubba) //!
0fcf0c2004-03-05Martin Nilsson string describe_error (mixed /* object|array */ err)
a66ff22000-01-11Martin Stjernholm {
677d262003-11-14Martin Stjernholm  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)));
a66ff22000-01-11Martin Stjernholm  }
677d262003-11-14Martin Stjernholm  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)) // 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;
a66ff22000-01-11Martin Stjernholm }
471ed91998-04-24Fredrik Hübinette (Hubbe) 
57b52d2003-05-31Martin Stjernholm #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 # 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" : \ 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
ead42e2004-07-04Martin Stjernholm //! @appears Pike.Encoder //!
57b52d2003-05-31Martin Stjernholm //! Codec for use with @[encode_value]. It understands all the
39979e2004-09-06Martin Stjernholm //! standard references to builtin functions, pike modules, and the //! main program script.
57b52d2003-05-31Martin Stjernholm //! //! The format of the produced identifiers are documented here to //! allow extension of this class: //! //! The produced names are either strings or arrays. The string //! variant specifies the thing to look up according to the first //! character: //! //! 'c' Look up in all_constants(). //! 's' Look up in _static_modules.
4ce9832003-06-05Martin Stjernholm //! 'r' Look up with resolv().
57b52d2003-05-31Martin Stjernholm //! 'p' Look up in programs. //! 'o' Look up in programs, then look up the result in objects. //! 'f' Look up in fc. //! //! In the array format, the first element is a string as above and //! the rest specify a series of things to do with the result: //! //! A string Look up this string in the result.
4ce9832003-06-05Martin Stjernholm //! 'm' Get module object in dirnode.
57b52d2003-05-31Martin Stjernholm //! 'p' Do object_program(result). //! //! All lowercase letters and the symbols ':', '/' and '.' are //! reserved for internal use in both cases where characters are used //! above.
471ed91998-04-24Fredrik Hübinette (Hubbe) {
57b52d2003-05-31Martin Stjernholm  mixed encoded;
eaa4da2001-10-04Fredrik Hübinette (Hubbe) 
57b52d2003-05-31Martin Stjernholm  static mapping(mixed:string) rev_constants = ([]); static mapping(mixed:string) rev_static_modules = ([]);
4ce9832003-06-05Martin Stjernholm  static array find_index (object|program parent, mixed child,
15cb2e2008-02-28Henrik Grubbström (Grubba)  array(object) module_object, int|void try)
57b52d2003-05-31Martin Stjernholm  { array id; find_id: {
4ce9832003-06-05Martin Stjernholm  array inds = indices (parent), vals = values (parent);
57b52d2003-05-31Martin Stjernholm  int i = search (vals, child);
4ce9832003-06-05Martin Stjernholm  if (i >= 0 && parent[inds[i]] == child) { id = ({inds[i]}); ENC_MSG (" found as parent value with index %O\n", id[0]); }
57b52d2003-05-31Martin Stjernholm  else { // Try again with the programs of the objects in parent, since // it's common that only objects and not their programs are // accessible in modules. foreach (vals; i; mixed val)
4ce9832003-06-05Martin Stjernholm  if (objectp (val) && child == object_program (val) && val == parent[inds[i]]) { if (module_object) { module_object[0] = val; id = ({inds[i]}); } else id = ({inds[i], 'p'}); ENC_MSG (" found as program of parent value object %O with index %O\n", val, id[0]);
57b52d2003-05-31Martin Stjernholm  break find_id; }
4ce9832003-06-05Martin Stjernholm 
15cb2e2008-02-28Henrik Grubbström (Grubba)  if (try) { ENC_MSG("Cannot find %O in %O.\n", child, parent); return UNDEFINED; }
57b52d2003-05-31Martin Stjernholm  error ("Cannot find %O in %O.\n", child, parent);
eaa4da2001-10-04Fredrik Hübinette (Hubbe)  } }
15cb2e2008-02-28Henrik Grubbström (Grubba)  if (!stringp (id[0])) { if (try) { ENC_MSG("Got nonstring index %O for %O in %O.\n", id[0], child, parent); return UNDEFINED; }
57b52d2003-05-31Martin Stjernholm  error ("Got nonstring index %O for %O in %O.\n", id[0], child, parent);
15cb2e2008-02-28Henrik Grubbström (Grubba)  }
471ed91998-04-24Fredrik Hübinette (Hubbe) 
57b52d2003-05-31Martin Stjernholm  return id; }
471ed91998-04-24Fredrik Hübinette (Hubbe) 
4ce9832003-06-05Martin Stjernholm  static string|array compare_resolved (string name, mixed what, mixed resolved, array(object) module_object) { array append; compare: { if (resolved == what) { ENC_MSG (" compare_resolved: %O is %O\n", what, resolved);
15cb2e2008-02-28Henrik Grubbström (Grubba)  /* No need for anything advanced. resolv() does the job. */ return "r" + name;
4ce9832003-06-05Martin Stjernholm  } if (objectp (resolved)) { if (object_program (resolved) == what) { ENC_MSG (" compare_resolved: %O is program of %O\n", what, resolved); append = ({'p'}); break compare; }
1997b32005-07-13Henrik Grubbström (Grubba)  if (resolved->is_resolv_dirnode) if (resolved->module == what) {
4ce9832003-06-05Martin Stjernholm  ENC_MSG (" compare_resolved: %O is dirnode module of %O\n", what, resolved); append = ({'m'});
1997b32005-07-13Henrik Grubbström (Grubba)  resolved = resolved->module;
4ce9832003-06-05Martin Stjernholm  break compare; }
1997b32005-07-13Henrik Grubbström (Grubba)  else if (object_program (resolved->module) == what) {
4ce9832003-06-05Martin Stjernholm  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",
1997b32005-07-13Henrik Grubbström (Grubba)  what, resolved->module);
4ce9832003-06-05Martin Stjernholm  #if 0 // This is only safe if the joinnode modules don't conflict, // and we don't know that. if (resolved->is_resolv_joinnode) { ENC_MSG (" compare_resolved: searching for %O in joinnode %O\n", what, resolved);
1997b32005-07-13Henrik Grubbström (Grubba)  foreach (resolved->joined_modules, mixed part)
4ce9832003-06-05Martin Stjernholm  if (string|array name = compare_resolved (name, what, part, module_object)) { if (module_object) module_object[0] = resolved; return name; } } #endif } ENC_MSG (" compare_resolved: %O is different from %O\n", what, resolved); return 0; } name = "r" + name;
0a38af2008-05-20Henrik Grubbström (Grubba)  string|array res = name;
4ce9832003-06-05Martin Stjernholm  if (append) if (module_object) { // The caller is going to do subindexing. In both the 'p' and // 'm' cases it's better to do that from the original // object/dirnode, so just drop the suffixes. module_object[0] = resolved; return res; } else return (arrayp (res) ? res : ({res})) + append; else return res; } string|array nameof (mixed what, void|array(object) module_object) //! When @[module_object] is set and the name would end with an //! @expr{object_program@} step (i.e. @expr{'p'@}), then drop that //! step so that the name corresponds to the object instead. //! @expr{@[module_object][0]@} will receive the found object.
57b52d2003-05-31Martin Stjernholm  { ENC_MSG ("nameof (%t %O)\n", what, what); if (what == encoded) { ENC_MSG (" got the thing to encode - encoding recursively\n");
ff38752002-02-14Henrik Grubbström (Grubba)  return UNDEFINED;
471ed91998-04-24Fredrik Hübinette (Hubbe)  }
57b52d2003-05-31Martin Stjernholm  if (string id = rev_constants[what]) ENC_RETURN (id); if (string id = rev_static_modules[what]) ENC_RETURN (id); if (objectp (what)) {
4ce9832003-06-05Martin Stjernholm  if (what->is_resolv_dirnode) { ENC_MSG (" is a dirnode\n");
1997b32005-07-13Henrik Grubbström (Grubba)  string name = program_path_to_name (what->dirname);
4ce9832003-06-05Martin Stjernholm  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");
1997b32005-07-13Henrik Grubbström (Grubba)  object modules = Builtin.array_iterator (what->joined_modules);
4ce9832003-06-05Martin Stjernholm  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; ENC_MSG (" joinnode has consistent name %O\n", name); if (string|array ref = compare_resolved (name, what, resolv (name), module_object