|
|
|
|
|
|
|
|
|
#pike __REAL_VERSION__ |
|
|
|
|
|
|
|
|
|
|
|
#define PIKE_AUTORELOAD |
#define GETCWD_CACHE |
|
|
|
#undef PIKE_MODULE_RELOC |
|
#ifndef PIKE_WARNINGS |
#define PIKE_WARNINGS 1 |
#endif /* PIKE_WARNINGS */ |
|
|
|
|
|
#if !defined(BT_MAX_STRING_LEN) || (BT_MAX_STRING_LEN <= 0) |
#undef BT_MAX_STRING_LEN |
#define BT_MAX_STRING_LEN 200 |
#endif /* !defined(BT_MAX_STRING_LEN) || (BT_MAX_STRING_LEN <= 0) */ |
constant bt_max_string_len = BT_MAX_STRING_LEN; |
|
|
|
|
|
|
|
#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; |
|
|
|
|
|
#if defined(__NT__) || defined(__amigaos__) || defined(__OS2__) |
#define PATH_SEPARATOR ";" |
#else |
#define PATH_SEPARATOR ":" |
#endif |
|
#ifdef __amigaos__ |
#define UPDIR "/" |
#else |
#define UPDIR "../" |
#endif |
|
|
|
|
|
|
|
int want_warnings = PIKE_WARNINGS; |
|
|
int compat_major=-1; |
|
|
int compat_minor=-1; |
|
|
int show_if_constant_errors = 0; |
|
int is_pike_master = 0; |
|
|
|
|
|
|
mapping(string:object) fs_map = ([]); |
object root_fs; |
|
|
|
private object(_static_modules.Builtin) Builtin = _static_modules.Builtin(); |
private constant Files = _static_modules._Stdio; |
|
#define Stat Files.Stat |
#define capitalize(X) (upper_case((X)[..0])+(X)[1..]) |
#define trim(X) (Builtin.string_trim (X)) |
|
private function write = Files()->_stdout->write; |
private function werror = Files()->_stderr->write; |
|
|
constant pike_cycle_depth = 0; |
|
|
|
|
|
#if defined (RESOLV_DEBUG) || defined (RECUR_COMPILE_DEBUG) |
|
#if constant (thread_local) |
protected object _msg_depth = thread_local(); |
|
#define GET_MSG_DEPTH (_msg_depth && _msg_depth->get()) |
#define INC_MSG_DEPTH() (_msg_depth && _msg_depth->set (_msg_depth->get() + 1)) |
#define DEC_MSG_DEPTH() (_msg_depth && _msg_depth->set (_msg_depth->get() - 1)) |
#else |
protected int _msg_depth; |
#define GET_MSG_DEPTH _msg_depth |
#define INC_MSG_DEPTH() (++_msg_depth) |
#define DEC_MSG_DEPTH() (--_msg_depth) |
#endif |
|
#endif |
|
#ifdef RESOLV_DEBUG |
|
#define GET_RESOLV_MSG_DEPTH GET_MSG_DEPTH |
#define INC_RESOLV_MSG_DEPTH() INC_MSG_DEPTH() |
#define DEC_RESOLV_MSG_DEPTH() DEC_MSG_DEPTH() |
|
void resolv_debug (sprintf_format fmt, sprintf_args... args) |
{ |
string pad = " " * GET_RESOLV_MSG_DEPTH; |
if (sizeof (args)) fmt = sprintf (fmt, @args); |
if (fmt[-1] == '\n') |
fmt = pad + replace (fmt[..<1], "\n", "\n" + pad) + "\n"; |
else |
fmt = pad + replace (fmt, "\n", "\n" + pad); |
if (!werror) werror = Files()->_stderr->write; |
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 |
|
constant no_value = (<>); |
constant NoValue = typeof (no_value); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected class Pike_7_8_master |
{ |
extern array(string) pike_include_path; |
extern array(string) pike_module_path; |
extern array(string) pike_program_path; |
#ifdef GETCWD_CACHE |
extern string current_path; |
int cd(string s); |
string getcwd(); |
#endif |
string combine_path_with_cwd(string path); |
#ifdef FILE_STAT_CACHE |
extern int invalidate_time; |
extern mapping(string:multiset(string)) dir_cache; |
#endif |
|
string|mapping(string:string) getenv(string|void s); |
void putenv(string|void varname, string|void value); |
|
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; |
|
extern mapping(program:object) objects; |
object cast_to_object(string oname, string current_file); |
class dirnode {}; |
extern string _master_file_name; |
void _main(array(string) orig_argv, array(string) env); |
extern mixed inhibit_compile_errors; |
void set_inhibit_compile_errors(mixed f); |
string trim_file_name(string s); |
void compile_error(string file,int line,string err); |
string handle_include(string f, string current_file, int local_include); |
|
int is_absolute_path(string p); |
array(string) explode_path(string p); |
string dirname(string x); |
string basename(string x); |
object low_cast_to_object(string oname, string current_file); |
extern int want_warnings; |
program compile_string(string data, void|string name); |
program compile_file(string file); |
|
constant master_efuns = ({}); |
class joinnode {}; |
extern mapping(string:mixed) fc; |
extern string _pike_file_name; |
void compile_warning(string file,int line,string err); |
string read_include(string f); |
|
class Codec {}; |
|
constant bt_max_string_len = 1; |
constant out_of_date_warning = 1; |
#ifdef PIKE_FAKEROOT |
extern object o; |
string fakeroot(string s); |
#endif |
#ifdef PIKE_AUTORELOAD |
extern int autoreload_on; |
extern int newest; |
extern mapping(string:int) load_time; |
#endif |
string master_read_file(); |
string normalize_path(string X); |
array(string) query_precompiled_names(string fname); |
program cast_to_program(string pname, string current_file, |
object|void handler); |
void handle_error(array(mixed)|object trace); |
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); |
|
mixed get_inhibit_compile_errors(); |
string decode_charset(string data, string charset); |
|
string describe_object(object o); |
string describe_backtrace(array(mixed) trace, void|int linewidth); |
string describe_error(mixed trace); |
|
|
|
#ifdef PIKE_MODULE_RELOC |
string relocate_module(string s); |
string unrelocate_module(string s); |
#endif |
extern int compat_major; |
extern int compat_minor; |
Stat master_file_stat(string x); |
object low_cast_to_object(string oname, string current_file, |
object|void current_handler); |
object findmodule(string fullname, object|void handler); |
extern multiset no_resolv; |
extern string ver; |
mapping get_default_module(); |
void runtime_warning(string where, string what, mixed ... args); |
protected int clipped; |
protected int canclip; |
protected string stupid_describe(mixed m, int maxlen); |
protected string stupid_describe_comma_list(array x, int maxlen); |
class Describer {}; |
string describe_function(function f); |
class CompatResolver {}; |
int(0..1) asyncp(); |
class Version {}; |
extern object currentversion; |
extern mapping(object:object) compat_handler_cache; |
object get_compilation_handler(int major, int minor); |
|
|
|
#ifdef RESOLV_DEBUG |
void resolv_debug (sprintf_format fmt, sprintf_args... args); |
#endif |
void error(sprintf_format f, sprintf_args ... args); |
constant no_value = (<>); |
constant NoValue = typeof (no_value); |
string programs_reverse_lookup (program prog); |
program objects_reverse_lookup (object obj); |
string fc_reverse_lookup (object obj); |
void unregister(program p); |
program low_cast_to_program(string pname, |
string current_file, |
object|void handler, |
void|int mkobj); |
extern string include_prefix; |
extern mapping(string:string) predefines; |
|
void add_predefine (string name, string value); |
void remove_predefine (string name); |
mapping get_predefines(); |
#if constant(thread_create) |
object backend_thread(); |
#endif |
function(string:string) set_trim_file_name_callback(function(string:string) s); |
int compile_exception (array|object trace); |
string program_path_to_name ( string path, |
void|string module_prefix, |
void|string module_suffix, |
void|string object_suffix ); |
string describe_module(object|program mod, array(object)|void ret_obj); |
string describe_program(program|function p); |
class Encoder {}; |
class Decoder {}; |
extern mapping(string:Codec) codecs; |
Codec get_codec(string|void fname, int|void mkobj); |
|
|
|
extern mixed encoded; |
string|array nameof (mixed what, void|array(object) module_object); |
mixed encode_object(object x); |
|
extern string fname; |
extern int mkobj; |
object __register_new_program(program p); |
object objectof (string|array what); |
function functionof (string|array what); |
program programof (string|array what); |
void decode_object(object o, mixed data); |
|
string _sprintf(int t); |
|
|
|
extern int show_if_constant_errors; |
extern mapping(string:string) initial_predefines; |
extern joinnode root_module; |
extern mapping(object:joinnode) handler_root_modules; |
extern array(string) system_module_path; |
extern CompatResolver fallback_resolver; |
joinnode get_root_module(object|void current_handler); |
local protected object Pike_7_8_compat_handler; |
local mixed resolv_or_error(string identifier, string|void current_file, |
void|object current_handler) |
{ |
if (!Pike_7_8_compat_handler) { |
Pike_7_8_compat_handler = global::get_compilation_handler(7, 8); |
} |
return Pike_7_8_compat_handler->resolv_or_error(identifier, current_file, |
current_handler); |
} |
local mixed resolv(string identifier, string|void current_file) |
{ |
if (!Pike_7_8_compat_handler) { |
Pike_7_8_compat_handler = global::get_compilation_handler(7, 8); |
} |
return Pike_7_8_compat_handler->resolv(identifier, current_file); |
} |
array get_backtrace (object|array err); |
object get_compat_master(int major, int minor) |
{ |
|
if (major < 8) |
return this::this; |
return get_compat_master(major, minor); |
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
protected class Pike_8_0_master |
{ |
inherit Pike_7_8_master; |
|
local protected object Pike_8_0_compat_handler; |
local mixed resolv_or_error(string identifier, string|void current_file, |
void|object current_handler) |
{ |
if (!Pike_8_0_compat_handler) { |
Pike_8_0_compat_handler = global::get_compilation_handler(8, 0); |
} |
return Pike_8_0_compat_handler->resolv_or_error(identifier, current_file, |
current_handler); |
} |
local mixed resolv(string identifier, string|void current_file) |
{ |
if (!Pike_8_0_compat_handler) { |
Pike_8_0_compat_handler = global::get_compilation_handler(8, 0); |
} |
return Pike_8_0_compat_handler->resolv(identifier, current_file); |
} |
object get_compat_master(int major, int minor) |
{ |
if (major < 8) |
return Pike_7_8_master::get_compat_master(major, minor); |
|
if ((major == 8) && (minor < 1)) |
return this::this; |
return get_compat_master(major, minor); |
} |
} |
|
|
|
|
|
|
|
|
protected inherit Pike_8_0_master; |
|
|
|
|
void error(sprintf_format f, sprintf_args ... args) { |
if (sizeof(args)) f = sprintf(f, @args); |
throw( ({ f, backtrace()[..<1] }) ); |
} |
|
|
#ifdef PIKE_FAKEROOT |
object o; |
string fakeroot(string s) |
{ |
string tmp1=combine_path_with_cwd(s); |
#ifdef PIKE_FAKEROOT_OMIT |
foreach(PIKE_FAKEROOT_OMIT/PATH_SEPARATOR, string x) |
if(glob(x,tmp1)) |
return s; |
#endif |
return PIKE_FAKEROOT+tmp1; |
} |
#else |
#define fakeroot(X) X |
#endif // PIKE_FAKEROOT |
|
#ifdef PIKE_MODULE_RELOC |
string relocate_module(string s) |
{ |
if(s == "/${PIKE_MODULE_PATH}" || has_prefix (s, "/${PIKE_MODULE_PATH}/")) { |
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) |
{ |
if(s == "/${PIKE_MODULE_PATH}" || has_prefix (s, "/${PIKE_MODULE_PATH}/")) |
return s; |
|
foreach(pike_module_path, string path) |
if(s == path) |
return "/${PIKE_MODULE_PATH}"; |
else { |
path = combine_path(path, ""); |
if(has_prefix (s, path)) |
return "/${PIKE_MODULE_PATH}/"+s[sizeof(path)..]; |
} |
|
|
foreach(pike_module_path, string path) { |
path = combine_path(path, UPDIR, ""); |
if(has_prefix (s, path)) |
return "/${PIKE_MODULE_PATH}/"+UPDIR+s[sizeof(path)..]; |
} |
|
return s; |
} |
|
#ifdef fakeroot |
#undef fakeroot |
#endif |
#define fakeroot relocate_module |
#endif // PIKE_MODULE_RELOC |
|
|
|
|
|
|
|
int is_absolute_path(string p) |
{ |
#ifdef __amigaos__ |
#define IS_ABSOLUTE_PATH(X) (search((X),":")>0) |
return IS_ABSOLUTE_PATH(p); |
#else |
#if defined(__NT__) || defined(__OS2__) |
p=replace(p,"\\","/"); |
if(sscanf(p,"%[a-zA-Z]:%*c",string s)==2 && sizeof(s)==1) |
return 1; |
#define IS_ABSOLUTE_PATH is_absolute_path |
#else |
#define IS_ABSOLUTE_PATH(X) has_prefix((X),"/") |
#endif |
return has_prefix(p,"/"); |
#endif |
} |
|
#if defined(__NT__) || defined(__OS2__) |
#define EXPLODE_PATH(X) (replace((X),"\\","/")/"/") |
#else |
#define EXPLODE_PATH(X) ((X)/"/") |
#endif |
|
|
|
|
|
|
|
|
|
array(string) explode_path(string p) |
{ |
#ifdef __amigaos__ |
int colon = search(reverse(p), ":"); |
if(colon >= 0) |
return ({ p[..<colon] }) + explode_path(p[<colon+1..]); |
array(string) r = p/"/"; |
return replace(r[..<1], "", "/")+r[<0..]; |
#else |
array(string) r = EXPLODE_PATH(p); |
if(r[0] == "" && sizeof(p)) |
r[0] = "/"; |
return r; |
#endif |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string dirname(string x) |
{ |
if(x=="") return ""; |
#ifdef __amigaos__ |
array(string) tmp=x/":"; |
array(string) tmp2=tmp[-1]/"/"; |
tmp[-1]=tmp2[..<1]*"/"; |
if(sizeof(tmp2) >= 2 && tmp2[-2]=="") tmp[-1]+="/"; |
return tmp*":"; |
#else |
array(string) tmp=EXPLODE_PATH(x); |
if(x[0]=='/' && sizeof(tmp)<3) return "/"; |
return tmp[..<1]*"/"; |
#endif |
} |
|
|
|
|
|
|
string basename(string x) |
{ |
#ifdef __amigaos__ |
return ((x/":")[-1]/"/")[-1]; |
#define BASENAME(X) ((((X)/":")[-1]/"/")[-1]) |
#else |
array(string) tmp=EXPLODE_PATH(x); |
return tmp[-1]; |
#define BASENAME(X) (EXPLODE_PATH(X)[-1]) |
#endif |
} |
|
#ifdef PIKE_AUTORELOAD |
|
int autoreload_on; |
int newest; |
|
#define AUTORELOAD_BEGIN() \ |
int ___newest=newest; \ |
newest=0 |
|
#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) |
|
#define AUTORELOAD_CHECK_PRECOMPILED_FILE(X) do { \ |
if(autoreload_on) { \ |
int mtime = get_precompiled_mtime (X); \ |
if (mtime >= 0 && mtime > newest) \ |
if(s->mtime>newest) newest=[int]s->mtime; \ |
} \ |
} while(0) |
|
#define AUTORELOAD_FINISH(VAR, CACHE, FILE) \ |
if(autoreload_on) { \ |
mixed val = CACHE[FILE]; \ |
if(!undefinedp (val) && val != no_value && \ |
newest <= load_time[FILE]) { \ |
VAR = val; \ |
} \ |
} \ |
load_time[FILE] = newest; \ |
if(___newest > newest) newest=___newest; |
|
|
mapping(string:int) load_time=([]); |
#else |
|
#define AUTORELOAD_CHECK_FILE(X) |
#define AUTORELOAD_BEGIN() |
#define AUTORELOAD_FINISH(VAR,CACHE,FILE) |
|
#endif // PIKE_AUTORELOAD |
|
|
|
|
|
|
|
|
|
|
program compile_string(string source, void|string filename, |
object|void handler, |
void|program p, |
void|object o, |
void|int _show_if_constant_errors) |
{ |
#ifdef RECUR_COMPILE_DEBUG |
werror ("%*s>>> compile_string %O\n", GET_MSG_DEPTH, "", filename); |
INC_MSG_DEPTH(); |
#endif |
string code = cpp(source, filename||"-", 1, handler, |
compat_major, compat_minor, |
(undefinedp(_show_if_constant_errors)? |
show_if_constant_errors: |
_show_if_constant_errors)); |
program ret; |
if(code) |
ret = compile(code, |
handler, |
compat_major, |
compat_minor, |
p, |
o); |
if (source_cache) |
source_cache[ret] = source; |
#ifdef RECUR_COMPILE_DEBUG |
DEC_MSG_DEPTH(); |
werror ("%*s<<< compile_string %O\n", GET_MSG_DEPTH, "", filename); |
#endif |
return ret; |
} |
|
|
string master_read_file(string file) |
{ |
string x = find_handler_for_path(file); |
if(x) |
{ |
object h = fs_map[x]; |
file = file[sizeof(x)+1..]; |
|
if(h = h->open(fakeroot(file),"r") ) |
{ |
string q = ([function(void : string)]h->read)(); |
return q; |
} |
|
} |
|
object o=Files()->Fd(); |
if( ([function(string, string : int)]o->open)(fakeroot(file),"r") ) |
return ([function(void : string)]o->read)(); |
return 0; |
} |
|
#ifdef GETCWD_CACHE |
protected string current_path; |
int cd(string s) |
{ |
current_path=0; |
return predef::cd(s); |
} |
|
string getcwd() |
{ |
return current_path || (current_path=predef::getcwd()); |
} |
#endif // GETCWD_CACHE |
|
constant high_master_get_dir = predef::get_dir; |
|
string combine_path_with_cwd(string ... paths) |
{ |
return combine_path(IS_ABSOLUTE_PATH(paths[0])?"":getcwd(),@paths); |
} |
|
#ifdef FILE_STAT_CACHE |
|
#define FILE_STAT_CACHE_TIME 20 |
|
int invalidate_time; |
mapping(string:multiset(string)) dir_cache = ([]); |
|
|
array(string) master_get_dir(string|void x) |
{ |
string y = find_handler_for_path(file); |
if(y) |
{ |
object h = fs_map[y]; |
x = x[sizeof(y)+1..]; |
return h->get_dir(x); |
} |
else return predef::get_dir(x); |
} |
|
Stat master_file_stat(string x) |
{ |
object y = find_handler_for_path(file); |
|
string dir = combine_path_with_cwd(x); |
string file = BASENAME(dir); |
dir = dirname(dir); |
|
if(time() > invalidate_time) |
{ |
dir_cache = ([]); |
invalidate_time = time()+FILE_STAT_CACHE_TIME; |
} |
|
multiset(string) d = dir_cache[dir]; |
if( undefinedp(d) ) |
{ |
array(string) tmp = master_get_dir(dir); |
if(tmp) |
{ |
#ifdef __NT__ |
tmp = map(tmp, lower_case); |
#endif |
d = dir_cache[dir] = (multiset)tmp; |
} |
else |
dir_cache[dir]=0; |
} |
|
#ifdef __NT__ |
file = lower_case(file); |
#endif |
if(d && !d[file]) return 0; |
|
|
if(y) |
{ |
object h = fs_map[y]; |
x = x[sizeof(y)+1..]; |
return h->stat(x); |
} |
else return predef::file_stat(x); |
} |
#else |
|
|
|
Stat master_file_stat(string file) |
{ |
string x = find_handler_for_path(file); |
if(x) |
{ |
object h = fs_map[x]; |
file = file[sizeof(x)+1..]; |
|
return h->stat(file); |
} |
else return predef::file_stat(file); |
} |
|
array master_get_dir(string file) |
{ |
string x = find_handler_for_path(file); |
if(x) |
{ |
object h = fs_map[x]; |
file = file[sizeof(x)+1..]; |
|
return h->get_dir(file); |
} |
else return predef::get_dir(file); |
} |
|
#endif // FILE_STAT_CACHE |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mixed add_filesystem_handler(string mountpoint, object filesystem) |
{ |
mixed rv = fs_map[mountpoint]; |
fs_map[mountpoint] = filesystem; |
return rv; |
} |
|
string find_handler_for_path(string file) |
{ |
|
|
foreach(reverse(sort(indices(fs_map))); int x; string path) |
{ |
string p = path; |
if(p[-1] != '/') p+="/"; |
if(file[-1] != '/') file+="/"; |
if(has_prefix(file, p)) |
return path; |
} |
|
return 0; |
} |
|
protected mapping(string:string) environment; |
|
#ifdef __NT__ |
protected void set_lc_env (mapping(string:string) env) |
{ |
environment = ([]); |
foreach (env; string var; string val) |
environment[lower_case (var)] = val; |
} |
#endif |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping(string:string) getenv (void|int force_update) |
{ |
mapping(string:string) res; |
|
if (force_update) { |
res = Builtin._getenv(); |
#ifdef __NT__ |
set_lc_env (res); |
#else |
environment = res + ([]); |
#endif |
} |
else { |
#ifdef __NT__ |
|
|
res = Builtin._getenv(); |
if (!environment) set_lc_env (res); |
#else |
if (!environment) environment = Builtin._getenv(); |
res = environment + ([]); |
#endif |
} |
|
return res; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
variant string getenv (string varname, void|int force_update) |
{ |
if (!environment || force_update) { |
#ifdef __NT__ |
set_lc_env (Builtin._getenv()); |
#else |
environment = Builtin._getenv(); |
#endif |
} |
|
#ifdef __NT__ |
varname = lower_case(varname); |
#endif |
|
return environment[varname]; |
} |
|
void putenv (string varname, void|string value) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
Builtin._putenv (varname, value); |
if (environment) { |
#ifdef __NT__ |
varname = lower_case (varname); |
#endif |
if (value) environment[varname] = value; |
else m_delete (environment, varname); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
program compile_file(string filename, |
object|void handler, |
void|program p, |
void|object o) |
{ |
AUTORELOAD_CHECK_FILE(filename); |
string code = cpp(master_read_file(filename), |
filename, |
1, |
handler, |
compat_major, |
compat_minor); |
if (!code) { |
error("Required feature missing.\n"); |
} |
return compile(code, |
handler, |
compat_major, |
compat_minor, |
p, |
o); |
} |
|
|
|
|
|
string normalize_path( string path ) |
{ |
#ifndef __NT__ |
return path; |
#else |
return replace(path,"\\","/"); |
#endif |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping(string:program|NoValue) programs=(["/master":this_program]); |
mapping(program:object) documentation = ([]); |
mapping(program:string) source_cache; |
|
mapping (program:object|NoValue) objects=([ |
this_program : this, |
object_program(_static_modules): _static_modules, |
]); |
|
mapping(string:object|NoValue) fc=([]); |
|
|
|
|
|
|
|
protected mapping(program:string) rev_programs = ([]); |
protected mapping(object:program) rev_objects = ([]); |
protected mapping(mixed:string) rev_fc = ([]); |
|
string programs_reverse_lookup (program prog) |
|
{ |
|
|
|
|
if (!rev_programs) return UNDEFINED; |
if (sizeof (rev_programs) < sizeof (programs)) { |
foreach (programs; string path; program|NoValue prog) |
if (prog == no_value) |
m_delete (programs, path); |
else |
rev_programs[prog] = path; |
} |
return rev_programs[prog]; |
} |
|
program objects_reverse_lookup (object obj) |
|
{ |
|
|
if (sizeof (rev_objects) < sizeof (objects)) { |
foreach (objects; program prog; object|NoValue obj) |
if (obj == no_value) |
m_delete (rev_objects, obj); |
else |
rev_objects[obj] = prog; |
} |
return rev_objects[obj]; |
} |
|
string fc_reverse_lookup (object obj) |
|
{ |
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]; |
} |
|
array(string) query_precompiled_names(string fname) |
|
|
{ |
#ifdef PRECOMPILED_SEARCH_MORE |
|
|
|
fname = fakeroot (fname); |
|
|
foreach (pike_module_path, string path) |
if (has_prefix (fname, path)) |
return map (pike_module_path, `+, "/", fname[sizeof (path)..], ".o"); |
#endif |
return ({ fname + ".o" }); |
} |
|
int get_precompiled_mtime (string id) |
|
|
|
{ |
Stat s = master_file_stat (fakeroot (id)); |
return s && s->isreg ? s->mtime : -1; |
} |
|
string read_precompiled (string id) |
|
|
{ |
return master_read_file (id); |
} |
|
protected class CompileCallbackError |
{ |
inherit _static_modules.Builtin.GenericError; |
constant is_generic_error = 1; |
constant is_compile_callback_error = 1; |
constant is_cpp_or_compilation_error = 1; |
} |
|
protected void compile_cb_error (string msg, mixed ... args) |
|
|
|
{ |
if (sizeof (args)) msg = sprintf (msg, @args); |
throw (CompileCallbackError (msg, backtrace()[..<1])); |
} |
|
protected void compile_cb_rethrow (object|array err) |
|
|
|
{ |
array bt; |
if (array|object e = catch (bt = get_backtrace (err))) |
handle_error (e); |
throw (CompileCallbackError (call_describe_error (err), bt)); |
} |
|
protected void call_compile_warning (object handler, string file, |
string msg, mixed ... args) |
{ |
if (sizeof (args)) msg = sprintf (msg, @args); |
msg = trim (msg); |
if (handler?->compile_warning) |
handler->compile_warning (file, 0, msg); |
else if (master()->compile_warning) |
master()->compile_warning (file, 0, msg); |
else |
compile_warning (file, 0, msg); |
} |
|
#if constant(_static_modules.Builtin.mutex) |
#define THREADED |
#endif |
|
#ifdef __NT__ |
#define FIX_CASE(X) lower_case(X) |
#else |
#define FIX_CASE(X) (X) |
#endif /* __NT__ */ |
|
protected string base_from_filename(string fname) |
{ |
string low_name = FIX_CASE(fname); |
if (has_prefix(low_name, ".#")) return 0; |
if (has_suffix(low_name, ".pike") || |
has_suffix(low_name, ".pmod")) { |
return fname[..<5]; |
} |
if (has_suffix(low_name, ".so")) { |
return fname[..<3]; |
} |
return 0; |
} |
|
protected int prio_from_filename(string fname) |
{ |
fname = FIX_CASE(fname); |
if (has_suffix(fname, ".pmod")) return 3; |
if (has_suffix(fname, ".so")) return 2; |
if (has_suffix(fname, ".pike")) return 1; |
|
|
return 0; |
} |
|
|
|
|
|
|
|
|
|
|
array(string) module_defined(object|program mod) |
{ |
array files = ({}); |
if (programp(mod)) |
return ({ Builtin.program_defined([program]mod) }); |
|
array mods; |
if (mod->is_resolv_joinnode) |
mods = mod->joined_modules; |
else |
mods = ({ mod }); |
|
foreach (mods;; object mod) |
{ |
if (mod->is_resolv_dirnode) |
files += ({ Builtin.program_defined(object_program(mod->module)) }); |
else |
files += ({ Builtin.program_defined(object_program(mod)) }); |
} |
return files; |
} |
|
|
void enable_source_cache() |
{ |
if (!source_cache) |
source_cache = ([]); |
} |
|
|
|
|
|
|
|
|
object show_doc(program|object|function obj) |
{ |
object doc_extractor = main_resolv("Tools.AutoDoc.PikeExtractor.extractClass"); |
string child; |
program prog; |
|
if (programp(obj)) |
prog = obj; |
if (functionp(obj)) |
{ |
prog = function_program(obj); |
child = ((describe_function(obj)||"")/"->")[-1]; |
} |
if (objectp(obj)) |
{ |
if (obj->is_resolv_joinnode) |
obj = obj->joined_modules[0]; |
if (obj->is_resolv_dirnode) |
prog = object_program(obj->module); |
else |
prog = object_program(obj); |
} |
|
|
if (prog && !documentation[prog] && doc_extractor) |
{ |
string source; |
if (source_cache && source_cache[prog]) |
source = source_cache[prog]; |
else |
{ |
array sourceref = array_sscanf(Builtin.program_defined(prog), |
"%s%[:]%[0-9]"); |
source = master_read_file(sourceref[0]); |
if (sizeof(sourceref[1]) && sizeof(sourceref[2])) |
{ |
if (programp(prog)) |
child = ((describe_program(prog)||"")/".")[-1]; |
} |
} |
|
if (source) |
{ |
catch |
{ |
documentation[prog] = doc_extractor(source, sprintf("%O", prog)); |
}; |
|
} |
} |
|
if (documentation[prog]) |
{ |
if (child) |
return documentation[prog]->findObject(child)||documentation[prog]->findChild(child); |
else |
return documentation[prog]; |
} |
} |
|
|
protected string call_describe_backtrace(array(mixed) trace, |
void|int linewidth) |
{ |
return (all_constants()["describe_backtrace"]||describe_backtrace) |
(trace, linewidth); |
} |
|
protected string call_describe_error(mixed err) |
{ |
return (all_constants()["describe_error"]||describe_error)(err); |
} |
|
protected program low_findprog(string pname, |
string ext, |
object|void handler, |
void|int mkobj) |
{ |
program ret; |
Stat s; |
string fname=pname+ext; |
|
resolv_debug("low_findprog(%O, %O, %O, %O)\n", |
pname, ext, handler, mkobj); |
|
#ifdef PIKE_MODULE_RELOC |
fname = unrelocate_module(fname); |
#endif |
|
#ifdef __NT__ |
|
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 |
|
if( (s=master_file_stat(fakeroot(fname))) && s->isreg ) |
{ |
#ifdef PIKE_AUTORELOAD |
if(!autoreload_on || load_time[fname] >= s->mtime) |
#endif |
{ |
if(!undefinedp (ret=programs[fname]) && ret != no_value) { |
resolv_debug ("low_findprog %s: returning cached (no autoreload)\n", fname); |
return ret; |
} |
} |
|
AUTORELOAD_BEGIN(); |
|
#ifdef PIKE_AUTORELOAD |
if (load_time[fname] >= s->mtime) |
if (!undefinedp (ret=programs[fname]) && ret != no_value) { |
resolv_debug ("low_findprog %s: returning cached (autoreload)\n", fname); |
return ret; |
} |
#endif |
|
object compiler_lock = DefaultCompilerEnvironment->lock(); |
if(!undefinedp(ret = programs[fname]) && (ret != no_value)) { |
destruct(compiler_lock); |
resolv_debug("low_findprog %s: returning cached (from other thread).\n", |
fname); |
return ret; |
} |
|
switch(ext) |
{ |
case "": |
case ".pike": |
foreach(query_precompiled_names(fname), string oname) { |
int o_mtime = get_precompiled_mtime (oname); |
if (o_mtime >= 0) { |
if (o_mtime >= s->mtime) { |
mixed err=catch { |
object|program decoded; |
AUTORELOAD_CHECK_PRECOMPILED_FILE (oname); |
resolv_debug ("low_findprog %s: decoding dumped\n", fname); |
INC_RESOLV_MSG_DEPTH(); |
decoded = decode_value(read_precompiled (oname), |
(handler?->get_codec || |
get_codec)(fname, mkobj, handler)); |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("low_findprog %s: dump decode ok\n", fname); |
if (decoded?->this_program_does_not_exist) { |
resolv_debug ("low_findprog %s: program claims not to exist\n", |
fname); |
return programs[fname] = 0; |
} |
else { |
if (objectp(decoded)) { |
resolv_debug("low_findprog %s: decoded object %O\n", |
fname, decoded); |
objects[ret = object_program(decoded)] = decoded; |
} else { |
ret = decoded; |
} |
resolv_debug("low_findprog %s: returning %O\n", fname, ret); |
return programs[fname]=ret; |
} |
}; |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("low_findprog %s: dump decode failed\n", fname); |
programs[fname] = no_value; |
call_compile_warning (handler, oname, |
"Decode failed: " + |
call_describe_error(err)); |
|
} else if (out_of_date_warning) { |
call_compile_warning (handler, oname, |
"Compiled file is out of date"); |
} |
} |
} |
|
resolv_debug ("low_findprog %s: compiling, mkobj: %O\n", fname, mkobj); |
INC_RESOLV_MSG_DEPTH(); |
programs[fname]=ret=__empty_program(0, fname); |
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; |
compile_cb_rethrow (err); |
} |
if ( mixed e=catch { |
ret=compile_string(src, fname, handler, |
ret, |
mkobj? (objects[ret]=__null_program()) : 0); |
} ) |
{ |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("low_findprog %s: compilation failed\n", fname); |
objects[ret] = no_value; |
ret=programs[fname]=0; |
destruct(compiler_lock); |
throw(e); |
} |
destruct(compiler_lock); |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("low_findprog %s: compilation ok\n", fname); |
break; |
|
#if constant(load_module) |
case ".so": |
if (fname == "") { |
werror( "low_findprog(%O, %O) => load_module(\"\")\n" |
"%s\n", pname, ext, call_describe_backtrace(backtrace()) ); |
} |
|
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; |
if (objectp (err) && err->is_module_load_error) |
|
|
|
|
|
|
|
|
|
call_compile_warning (handler, fname, |
"Failed to load library: %s\n", err->reason); |
else |
compile_cb_rethrow (err); |
} |
else |
resolv_debug ("low_findprog %s: loaded binary\n", fname); |
#endif /* load_module */ |
} |
|
AUTORELOAD_FINISH(ret,programs,fname); |
|
if (ret?->this_program_does_not_exist) { |
resolv_debug ("low_findprog %s: program says it doesn't exist\n", fname); |
return programs[fname] = 0; |
} |
else { |
if(!ret) |
resolv_debug("low_findprog %s: dependencies failed.\n", fname); |
else |
resolv_debug("low_findprog %s: returning %O\n", fname, ret); |
return programs[fname]=ret; |
} |
} |
|
resolv_debug ("low_findprog %s: file not found\n", fname); |
return 0; |
} |
|
|
|
|
|
|
void unregister(program p) |
{ |
|
object compiler_lock = DefaultCompilerEnvironment->lock(); |
|
if(string fname=rev_programs[p] || search(programs,p)) { |
resolv_debug("unregister %s\n", fname); |
if (m_delete (rev_programs, p)) |
m_delete (programs, fname); |
else |
programs[fname] = no_value; |
|
string name = program_path_to_name (fname); |
mixed n = has_value (name, '.') ? |
resolv ((name / ".")[..<1] * ".") : |
get_root_module(); |
if (objectp (n) && (n->is_resolv_dirnode || n->is_resolv_joinnode)) |
n->delete_value (p); |
|
fname = dirname (fname); |
if ( fname!="" && objectp (n = fc[fname]) ) |
if (n->is_resolv_dirnode) |
n->delete_value (p); |
} |
|
object o = m_delete(objects, p); |
if (objectp (o)) { |
m_delete(rev_objects, o); |
} |
|
foreach (fc; string name; mixed mod) |
if (objectp(mod) && object_program(mod) == p) |
if (m_delete (rev_fc, mod)) |
m_delete (fc, name); |
else |
fc[name] = no_value; |
|
|
} |
|
protected program findprog(string pname, |
string ext, |
object|void handler, |
void|int mkobj) |
{ |
switch(ext) |
{ |
case ".pike": |
case ".so": |
return low_findprog(pname,ext,handler, mkobj); |
|
default: |
pname+=ext; |
return |
low_findprog(pname,"", handler, mkobj) || |
low_findprog(pname,".pike", handler, mkobj) || |
low_findprog(pname,".so", handler, mkobj); |
} |
} |
|
program low_cast_to_program(string pname, |
string current_file, |
object|void handler, |
void|int mkobj) |
{ |
string ext; |
string nname; |
|
|
|
|
if(sscanf(reverse(BASENAME(pname)),"%s.%s",ext, nname)) |
{ |
ext="."+reverse(ext); |
pname=pname[..<sizeof(ext)]; |
} |
else { |
ext=""; |
} |
|
|
|
if(IS_ABSOLUTE_PATH(pname)) |
{ |
program|NoValue prog = programs[pname]; |
if ((!undefinedp(prog)) && (prog != no_value)) |
{ |
return prog; |
} |
pname=combine_path("",pname); |
return findprog(pname,ext,handler,mkobj); |
} |
else { |
string cwd; |
if(current_file) |
{ |
cwd=dirname(current_file); |
} |
else { |
cwd=getcwd(); |
} |
|
if(program ret=findprog(combine_path(cwd,pname),ext,handler,mkobj)) |
return ret; |
|
foreach(pike_program_path, string path) |
if(program ret=findprog(combine_path(path,pname),ext,handler,mkobj)) |
return ret; |
|
return 0; |
} |
} |
|
|
|
|
|
|
program cast_to_program(string pname, |
string current_file, |
object|void handler) |
{ |
resolv_debug ("cast_to_program(%O, %O)\n", pname, current_file); |
INC_RESOLV_MSG_DEPTH(); |
program ret = low_cast_to_program(pname, current_file, handler); |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("cast_to_program(%O, %O) => %O\n", pname, current_file, ret); |
if (programp (ret)) return ret; |
error("Cast %O to program failed%s.\n", |
pname, |
(current_file && current_file!="-") ? sprintf(" in %O",current_file) : ""); |
} |
|
|
protected string narrowify_string(string s) |
{ |
if (Builtin.string_width(s) <= 8) return s; |
|
return map(s/"", |
lambda(string s) { |
if (Builtin.string_width(s) <= 8) return s; |
int c = s[0] & 0xffffffff; |
if (c <= 0xffff) return sprintf("\\u%04x", c); |
return sprintf("\\U%08x", c); |
}) * ""; |
} |
|
|
|
void handle_error(array|object trace) |
{ |
|
|
if(mixed x=catch { |
werror(call_describe_backtrace(trace)); |
}) { |
|
|
|
werror("Error in handle_error in master object:\n"); |
if(catch { |
|
|
catch { |
if (catch { |
string msg = [string]x[0]; |
array bt = [array]x[1]; |
werror("%s", narrowify_string(msg)); |
werror(narrowify_string(sprintf("%O\n", bt))); |
}) { |
werror(narrowify_string(sprintf("%O\n", x))); |
} |
}; |
werror(narrowify_string(sprintf("Original error:\n" |
"%O\n", trace))); |
}) { |
werror("sprintf() failed to write error.\n"); |
} |
} |
|
} |
|
|
|
|
constant master_efuns = ({ |
"error", |
"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", |
"describe_error", |
"get_backtrace", |
"normalize_path", |
"true", |
"false", |
"getenv", |
"putenv", |
|
#ifdef GETCWD_CACHE |
"cd", |
"getcwd", |
#endif |
}); |
|
enum bool { false=0, true=1 }; |
|
|
string include_prefix; |
|
|
string doc_prefix; |
|
|
string cflags; |
|
|
string ldflags; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void create() |
{ |
foreach(master_efuns, string e) |
if (has_index(this, e)) |
add_constant(e, this[e]); |
else |
error("Function %O is missing from master.pike.\n", e); |
|
|
|
|
|
|
|
|
add_constant("bool", typeof([int(0..1)](mixed)0)); |
|
add_constant("__dirnode", dirnode); |
add_constant("__joinnode", joinnode); |
|
add_constant("write", write); |
add_constant("werror", werror); |
|
|
|
add_constant("get_dir", high_master_get_dir ); |
add_constant("file_stat", lambda( string f, int|void d ) { return file_stat(f,d);} ); |
|
object rnd = Builtin.RandomSystem(); |
add_constant("random", rnd->random); |
add_constant("random_string", rnd->random_string); |
|
#define CO(X) add_constant(#X,Builtin.__backend->X) |
CO(call_out); |
CO(_do_call_outs); |
CO(find_call_out); |
CO(remove_call_out); |
CO(call_out_info); |
|
#if "#share_prefix#"[0]!='#' |
|
add_include_path("#share_prefix#/include"); |
add_module_path("#share_prefix#/modules"); |
#endif |
|
#if "#lib_prefix#"[0]!='#' |
|
add_include_path("#lib_prefix#/include"); |
add_module_path("#lib_prefix#/modules"); |
#endif |
|
#if "#cflags# "[0]!='#' |
cflags = "#cflags#"; |
#endif |
|
#if "#ldflags# "[0]!='#' |
ldflags = "#ldflags#"; |
#endif |
|
#if "#include_prefix#"[0]!='#' |
include_prefix = "#include_prefix#"; |
cflags = (cflags || "") + " -I" + dirname(include_prefix); |
#endif |
|
#if "#doc_prefix#"[0]!='#' |
doc_prefix = "#doc_prefix#"; |
#endif |
|
#if constant(__embedded_resource_directory) |
|
|
add_include_path(__embedded_resource_directory + "/lib/include"); |
add_module_path(__embedded_resource_directory + "/lib/modules"); |
add_module_path(__embedded_resource_directory + "/" + replace(uname()->machine, " ", "_") + "/modules"); |
|
#endif |
system_module_path=pike_module_path; |
} |
|
|
|
|
|
|
|
|
|
|
program handle_inherit(string pname, string current_file, object|void handler) |
{ |
resolv_debug ("handle_inherit(%O, %O)\n", pname, current_file); |
INC_RESOLV_MSG_DEPTH(); |
program ret = cast_to_program(pname, current_file, handler); |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("handle_inherit(%O, %O) => %O\n", pname, current_file, ret); |
return ret; |
} |
|
object low_cast_to_object(string oname, string current_file, |
object|void current_handler) |
{ |
program p; |
object o; |
|
p = low_cast_to_program(oname, current_file, current_handler, 1); |
if(!p) return 0; |
if(!objectp(o = objects[p])) { |
object compiler_lock = DefaultCompilerEnvironment->lock(); |
|
if(!objectp(o = objects[p])) o = objects[p] = p(); |
destruct(compiler_lock); |
} |
return o; |
} |
|
|
|
|
object cast_to_object(string oname, string current_file, |
object|void current_handler) |
{ |
resolv_debug ("cast_to_object(%O, %O)\n", oname, current_file); |
INC_RESOLV_MSG_DEPTH(); |
object o = low_cast_to_object(oname, current_file, current_handler); |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("cast_to_object(%O, %O) => %O\n", oname, current_file, o); |
if (objectp (o)) return o; |
error("Cast %O to object failed%s.\n", |
oname, |
(current_file && current_file!="-") ? sprintf(" in %O",current_file) : ""); |
} |
|
|
|
protected class ZERO_TYPE {}; |
|
protected object Unicode; |
|
|
|
|
|
class dirnode (string dirname, object|void compilation_handler, |
string|void name) |
{ |
constant is_resolv_dirnode = 1; |
|
|
mixed module; |
mapping(string:mixed) cache=([]); |
|
|
|
protected mapping(string:array(string)) file_paths = ([]); |
|
#ifdef __NT__ |
#define FIX_CASE(X) lower_case(X) |
#else |
#define FIX_CASE(X) (X) |
#endif /* __NT__ */ |
|
protected string base_from_filename(string fname) |
{ |
string low_name = FIX_CASE(fname); |
catch { |
|
low_name = utf8_to_string(low_name); |
if (Builtin.string_width(low_name) > 8) { |
|
|
|
if (!Unicode) { |
Unicode = resolv("Unicode"); |
} |
low_name = Unicode.normalize(low_name, "NFC"); |
} |
}; |
if (has_prefix(low_name, ".#")) return 0; |
if (has_suffix(low_name, ".pike") || |
has_suffix(low_name, ".pmod")) { |
return fname[..<5]; |
} |
if (has_suffix(low_name, ".so")) { |
return fname[..<3]; |
} |
return 0; |
} |
|
protected int prio_from_filename(string fname) |
{ |
fname = FIX_CASE(fname); |
if (has_suffix(fname, ".pmod")) return 3; |
if (has_suffix(fname, ".so")) return 2; |
if (has_suffix(fname, ".pike")) return 1; |
return 0; |
} |
|
protected void create() |
{ |
if (!dirname) { |
error("Attempt to create a dirnode without a directory.\n" |
"Have you inherited a dirnode?\n"); |
} |
|
resolv_debug ("dirnode(%O,%O) created with name %O\n", dirname, |
compilation_handler, name); |
fc[dirname]=this; |
if (!sizeof(dirname)) return; |
array(string) files = sort(master_get_dir(dirname)||({})); |
array(string) bases = map(files, base_from_filename); |
files = filter(files, bases); |
bases = filter(bases, bases); |
resolv_debug("dirnode(%O,%O) got %d files.\n", |
dirname, compilation_handler, sizeof(bases)); |
if (!sizeof(files)) return; |
|
foreach(files; int no; string fname) { |
fname = combine_path(dirname, fname); |
string base = bases[no]; |
if (base == "module") { |
|
module = module_checker(); |
} |
array(string) paths = file_paths[base]; |
if (!paths) { |
|
file_paths[base] = ({ fname }); |
continue; |
} |
|
|
|
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..]; |
} |
} |
|
protected class module_checker |
{ |
protected int `!() |
{ |
resolv_debug ("dirnode(%O)->module_checker()->`!()\n",dirname); |
|
if (mixed err = catch { |
|
if (module = cache["module"] || low_ind("module", 1)) { |
|
|
|
|
cache=([]); |
_cache_full=0; |
} |
resolv_debug("dirnode(%O)->module_checker()->`!() => %s\n", |
dirname, !module ? "doesn't exist" : "exists"); |
return !module; |
}) { |
|
|
|
|
|
|
|
|
resolv_debug("dirnode(%O)->module_checker()->`!() => failure, doesn't exist\n", |
dirname); |
return 1; |
} |
} |
|
protected mixed `[](string index) |
{ |
resolv_debug ("dirnode(%O)->module_checker()[%O] => %O\n", |
dirname, index, module[?index]); |
return module[?index]; |
} |
protected array(string) _indices() { if(module) return indices(module); } |
protected array _values() { if(module) return values(module); } |
} |
|
protected mixed low_ind(string index, int(0..1)|void set_module) |
{ |
array(string) paths; |
|
INC_RESOLV_MSG_DEPTH(); |
|
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) { |
if (dirnode n = fc[fname]) { |
|
|
|
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, |
name && (name == "predef::" ? |
index : name + "." + index)); |
} |
resolv_debug("dirnode(%O)->ind(%O) casting (object)%O\n", |
dirname, index, fname); |
|
|
|
|
|
mixed ret; |
if (ret = catch { |
if (objectp(ret = low_cast_to_object(fname, 0, compilation_handler))) { |
|
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, call_describe_backtrace(ret)); |
} |
} else { |
resolv_debug("dirnode(%O)->ind(%O) casting (program)%O\n", |
dirname, index, fname); |
program|object ret; |
if (ret = low_cast_to_program(fname, 0, compilation_handler)) { |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug("dirnode(%O)->ind(%O) => found subprogram %O:%O\n", |
dirname, index, fname, ret); |
#if constant(load_module) |
if (has_suffix(fname, ".so")) { |
|
if (!ret->_module_value) { |
object o; |
|
if(!objectp(o = objects[ret])) { |
object compiler_lock = DefaultCompilerEnvironment->lock(); |
if(!objectp(o = objects[ret])) o = objects[ret] = ret(); |
destruct(compiler_lock); |
} |
ret = o; |
} |
if(mixed tmp=ret->_module_value) ret=tmp; |
} |
#endif |
return ret; |
} |
} |
resolv_debug("dirnode(%O)->ind(%O) => failure for file %O\n", |
dirname, index, fname); |
} |
|
resolv_debug("dirnode(%O)->ind(%O) => UNDEFINED\n", |
dirname, index); |
return UNDEFINED; |
} |
|
protected mixed ind(string index) |
{ |
resolv_debug ("dirnode(%O)->ind(%O)\n", dirname, index); |
INC_RESOLV_MSG_DEPTH(); |
|
if (_cache_full) { |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug("dirnode(%O)->ind(%O) => cache_full %O\n", |
dirname, index, cache[index]); |
return cache[index]; |
} |
|
if(module) |
{ |
mixed o; |
if(!undefinedp(o=module[index])) |
{ |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("dirnode(%O)->ind(%O) => found %O\n", |
dirname, index, o); |
return o; |
} |
resolv_debug ("dirnode(%O)->ind(%O) => not found in module\n", |
dirname, index); |
} |
else |
resolv_debug ("dirnode(%O)->ind(%O) => no module\n", dirname, index); |
|
DEC_RESOLV_MSG_DEPTH(); |
return low_ind(index); |
} |
|
protected mixed `[]=(string index, mixed value) |
{ |
if(module && has_index(module, index)) |
return module[index]=value,cache[index]=value; |
error("No such variable (%s) in object.\n", index); |
} |
|
protected mixed `->=(string index, mixed value) |
{ |
return `[]=(index, value); |
} |
|
protected mixed `[](string index) |
{ |
mixed ret; |
#ifdef MODULE_TRACE |
werror("%*nDirnode(%O) cache[%O] ?????\n", |
sizeof(backtrace()),dirname,index); |
#endif |
if(!undefinedp(ret=cache[index])) |
{ |
#ifdef MODULE_TRACE |
werror("%*nDirnode(%O) cache[%O] => %O%s\n", |
sizeof(backtrace()),dirname,index, ret, |
(ret != ZERO_TYPE)?"":" (zero_type)"); |
#endif |
if (ret != ZERO_TYPE) return ret; |
#ifdef MODULE_TRACE |
werror("%*nDirnode(%O) ZERO_TYPE!\n", |
sizeof(backtrace()),dirname); |
#endif |
return UNDEFINED; |
} |
ret=ind(index); |
|
|
|
if(ret == predef::__placeholder_object) { |
#ifdef MODULE_TRACE |
werror("%*nDirnode(%O) PLACE_HOLDER.\n", |
sizeof(backtrace()),dirname); |
#endif |
return ret; |
} |
|
cache[index] = undefinedp(ret) ? ZERO_TYPE : ret; |
return ret; |
} |
|
protected mixed `->(string index) |
{ |
if( (< "dirname", "name", "is_resolv_dirnode", |
"module", "delete_value" >)[index] ) |
return ::`->(index); |
return `[](index); |
} |
|
protected mixed safe_index(string index) |
{ |
mixed err; |
resolv_debug ("dirnode(%O): %O...\n", dirname, index); |
if (err = catch { return `[](index); }) { |
call_compile_warning (compilation_handler, |
dirname+"."+fname, |
"Compilation failed: " + |
call_describe_error(err)); |
} |
return UNDEFINED; |
} |
|
protected int(0..1) _cache_full; |
protected void fill_cache() |
{ |
if (_cache_full) { |
return; |
} |
|
resolv_debug ("dirnode(%O) => Filling cache...\n", dirname); |
|
|
|
|
|
if (module) { |
resolv_debug("dirnode(%O): module: %O, indices:%{%O, %}\n", |
dirname, module, indices(module)); |
map(indices(module), safe_index); |
} |
|
map(indices(file_paths), safe_index); |
_cache_full = (object_program(module) != __null_program); |
resolv_debug ("dirnode(%O) => Cache %s.\n", dirname, |
_cache_full?"full":"partially filled"); |
} |
|
protected array(string) _indices() |
{ |
fill_cache(); |
|
|
|
|
return filter (indices (cache), map (values (cache), `!=, ZERO_TYPE)); |
} |
|
protected array(mixed) _values() |
{ |
fill_cache(); |
return values(cache) - ({ZERO_TYPE}); |
} |
|
void delete_value (mixed val) |
{ |
if (string name = search (cache, val)) { |
m_delete (cache, name); |
_cache_full = 0; |
} |
} |
|
protected int(0..) _sizeof() { |
return sizeof(_values()); |
} |
|
protected string _sprintf(int as) |
{ |
return as=='O' && (name || sprintf("master()->dirnode(%O:%O)", |
dirname, module && module)); |
} |
} |
|
|
|
|
|
|
class joinnode (array(object|mapping) joined_modules, |
object|void compilation_handler, |
joinnode|mapping(mixed:int(0..0))|void fallback_module, |
string|void name) |
{ |
constant is_resolv_joinnode = 1; |
|
mapping(string:mixed) cache=([]); |
|
protected string _sprintf(int as) |
{ |
if (as != 'O') return 0; |
if (name) { |
if (has_value (name, '|')) |
return "joinnode(" + name + ")"; |
else |
return name; |
} |
else |
return sprintf("master()->joinnode(%O)", joined_modules); |
} |
|
protected void create() |
{ |
if( !fallback_module ) { |
|
|
fallback_module = ([]); |
} |
|
if (!joined_modules) { |
error("Attempt to create a joinnode without joined modules.\n" |
"Have you inherited a joinnode?\n"); |
} |
|
if (!name) |
{ |
mapping(string:int(1..1)) names = ([]); |
foreach (joined_modules, object|mapping m) { |
if (objectp (m) && stringp (m->name)) |
names[m->name] = 1; |
} |
if (sizeof (names)) |
name = sort (indices (names)) * "|"; |
} |
|
resolv_debug ("joinnode(%O) created with name %O\n", joined_modules, name); |
} |
|
void add_path(string path) |
{ |
path = combine_path(getcwd(), path); |
dirnode node = fc[path] || |
(fc[path] = dirnode(path, compilation_handler, |
name && !has_value (name, '|') && name)); |
if (sizeof(joined_modules) && |
joined_modules[0] == node) return; |
joined_modules = ({ node }) + (joined_modules - ({ node })); |
cache = ([]); |
} |
|
void rem_path(string path) |
{ |
path = combine_path(getcwd(), path); |
joined_modules = filter(joined_modules, |
lambda(dirnode node) { |
return !objectp(node) || |
!node->is_resolv_dirnode || |
(node->dirname != path); |
}); |
cache = ([]); |
} |
|
protected mixed ind(string index) |
{ |
resolv_debug ("joinnode(%O)->ind(%O)\n", joined_modules, index); |
INC_RESOLV_MSG_DEPTH(); |
|
array(mixed) res = ({}); |
foreach(joined_modules, object|mapping o) |
{ |
mixed ret; |
if (!undefinedp(ret = o[index])) |
{ |
if (objectp(ret) && |
(ret->is_resolv_dirnode || ret->is_resolv_joinnode)) |
{ |
|
res += ({ ret }); |
} else { |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("joinnode(%O)->ind(%O) => found %O\n", |
joined_modules, index, ret); |
return (ret); |
} |
} |
} |
|
if (sizeof(res)) { |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug("joinnode(%O)->ind(%O) => new joinnode, fallback: %O\n", |
joined_modules, index, fallback_module[index]); |
return joinnode(res, compilation_handler, fallback_module[index], |
name && !has_value (name, '|') && |
(name == "predef::" ? index : name + "." + index)); |
} |
|
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("joinnode(%O)->ind(%O) => not found. Trying fallback %O\n", |
joined_modules, index, fallback_module); |
return fallback_module[index]; |
} |
|
protected mixed `[]=(string index, mixed value) |
{ |
foreach(joined_modules, object|mapping o) |
if(has_index(o, index)) |
return o[index]=value,cache[index]=value; |
error("No such variable (%s) in object.\n", index); |
} |
|
protected mixed `->=(string index, mixed value) |
{ |
if( index=="fallback_module" ) |
return fallback_module=value; |
return `[]=(index, value); |
} |
|
protected mixed `[](string index) |
{ |
mixed ret; |
if (!undefinedp(ret = cache[index])) { |
if (ret != ZERO_TYPE) { |
return ret; |
} |
return UNDEFINED; |
} |
ret = ind(index); |
|
|
|
if(ret == predef::__placeholder_object) return ret; |
|
if (undefinedp(ret)) { |
cache[index] = ZERO_TYPE; |
} else { |
cache[index] = ret; |
} |
return ret; |
} |
|
protected mixed `->(string index) |
{ |
if( (< "joined_modules", "fallback_module", "name", "is_resolv_joinnode", |
"add_path", "rem_path", "delete_value", "_encode", |
"_decode" >)[index] ) |
return ::`->(index); |
return `[](index); |
} |
|
protected int _cache_full; |
|
protected void fill_cache() |
{ |
if (_cache_full) { |
return; |
} |
foreach(joined_modules, object|mapping|program o) { |
foreach(indices(o), string index) { |
if (!has_index(cache, index)) { |
`[](index); |
} |
} |
} |
foreach(indices(fallback_module), string index) { |
`[](index); |
} |
_cache_full = 1; |
} |
|
protected array(string) _indices() |
{ |
fill_cache(); |
|
|
|
|
return filter (indices (cache), map (values (cache), `!=, ZERO_TYPE)); |
} |
|
protected array(mixed) _values() |
{ |
fill_cache(); |
return values(cache) - ({ZERO_TYPE}); |
} |
|
protected int(0..) _sizeof() |
{ |
return sizeof(_values()); |
} |
|
void delete_value (mixed val) |
{ |
if (string name = search (cache, val)) |
m_delete (cache, name); |
for (int i = 0; i < sizeof (joined_modules); i++) { |
object|mapping|program o = joined_modules[i]; |
if (o == val) { |
joined_modules = joined_modules[..i - 1] + joined_modules[i + 1..]; |
i--; |
} |
else if (objectp (o) && (o->is_resolv_dirnode || o->is_resolv_joinnode)) |
o->delete_value (val); |
else if (string name = mappingp (o) && search (o, val)) |
m_delete (o, name); |
} |
} |
|
protected int `== (mixed other) |
{ |
return objectp (other) && (other->is_resolv_joinnode == 1) && |
equal (mkmultiset (joined_modules), mkmultiset (other->joined_modules)); |
} |
|
array(object) _encode() |
{ |
return joined_modules; |
} |
|
void _decode (array(object) joined_modules) |
{ |
this::joined_modules = joined_modules; |
} |
} |
|
joinnode handle_import(string path, string|void current_file, |
object|void current_handler) |
{ |
#ifdef __amigaos__ |
if(path == ".") |
path = ""; |
#endif |
if(current_file) |
{ |
path = combine_path_with_cwd(dirname(current_file), path); |
} else { |
path = combine_path_with_cwd(path); |
} |
|
|
#if 0 |
|
|
|
|
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(path == "/${PIKE_MODULE_PATH}" || |
has_prefix(path, "/${PIKE_MODULE_PATH}/")) { |
string tmp = path[21..]; |
foreach(pike_module_path, string prefix) { |
node->add_path(sizeof(tmp)? combine_path(prefix, tmp) : prefix); |
} |
} else |
#endif /* PIKE_MODULE_RELOC */ |
node->add_path(path); |
return node; |
} |
|
program|object findmodule(string fullname, object|void handler, |
void|string name) |
{ |
program|object o; |
|
resolv_debug ("findmodule(%O)\n", fullname); |
if(!undefinedp(o=fc[fullname]) && o != no_value) |
{ |
if (objectp(o) || programp(o) || o != 0) { |
resolv_debug ("findmodule(%O) => found %O (cached)\n", fullname, o); |
return o; |
} |
resolv_debug ("findmodule(%O) => not found (cached)\n", fullname); |
return UNDEFINED; |
} |
|
if(Stat stat=master_file_stat(fakeroot(fullname))) |
{ |
if(stat->isdir) |
{ |
resolv_debug ("findmodule(%O) => new dirnode\n", fullname); |
return fc[fullname] = dirnode(fullname, handler, name); |
} |
#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; |
} |
#endif |
} |
|
INC_RESOLV_MSG_DEPTH(); |
|
if(objectp (o = low_cast_to_object(fullname, "/.", handler))) { |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("findmodule(%O) => got object %O\n", fullname, o); |
return fc[fullname]=o; |
} |
|
if (programp (o = low_cast_to_program(fullname, "/.", handler))) { |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("findmodule(%O) => got .pike program %O\n", fullname, o); |
return fc[fullname] = o; |
} |
|
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("findmodule(%O) => not found\n", fullname); |
return fc[fullname] = 0; |
} |
|
#if 0 |
mixed handle_import(string what, string|void current_file, object|void handler) |
{ |
string path; |
if(current_file) |
{ |
path = combine_path_with_cwd(dirname(current_file), what); |
} else { |
path = combine_path_with_cwd(what); |
} |
|
#if 0 |
|
|
|
if (handler) { |
resolv_debug ("handle_import(%O, %O, %O) => new dirnode with handler\n", |
what, current_file, handler); |
return dirnode(path, handler); |
} |
#endif |
|
if(objectp (fc[path])) { |
resolv_debug ("handle_import(%O, %O) => found %O (cached)\n", |
object s = file_stat(tmp); |
if(s && s->isreg) |
{ |
object fs; |
catch(fs = resolv("Filesystem.Zip")(tmp)); |
if(fs) add_filesystem_handler(tmp, fs); |
tmp = combine_path(tmp, "include"); |
} |
what, current_file, fc[path]); |
return fc[path]; |
} |
resolv_debug ("handle_import(%O, %O) => new dirnode\n", what, current_file); |
#ifdef PIKE_MODULE_RELOC |
|
|
|
if(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(fs_map[tmp]) |
tmp = combine_path(tmp, "modules"); |
|
if(master_file_stat(s2)) |
dirnodes += ({ dirnode(s2, handler) }); |
} |
resolv_debug("handle_import(%O, %O) => Found %d dirnodes\n", |
what, current_file, sizeof(dirnodes)); |
if (sizeof(dirnodes) > 1) return fc[path] = joinnode(dirnodes); |
if (sizeof(dirnodes)) return fc[path] = dirnodes[0]; |
return UNDEFINED; |
} |
#endif /* PIKE_MODULE_RELOC */ |
return fc[path] = dirnode(fakeroot(path), handler); |
} |
#endif /* 0 */ |
|
multiset no_resolv = (<>); |
|
|
class CompatResolver |
{ |
|
joinnode root_module = |
joinnode(({instantiate_static_modules(predef::_static_modules)}), |
0, 0, "predef::"); |
|
|
mapping(object:joinnode) handler_root_modules = ([]); |
|
|
array(string) system_module_path=({}); |
|
|
array(string) pike_module_path=({}); |
|
|
array(string) pike_include_path=({}); |
|
|
array(string) pike_program_path=({}); |
|
mapping(string:string) predefines = master()->initial_predefines; |
string ver; |
|
|
|
|
|
CompatResolver fallback_resolver; |
|
|
|
|
|
protected void create(mixed version, CompatResolver|void fallback_resolver) |
{ |
resolv_debug("CompatResolver(%O, %O)\n", version, fallback_resolver); |
ver=(string)version; |
#if 0 |
if (version) { |
root_module->symbol = ver + "::"; |
} |
#endif |
if (CompatResolver::fallback_resolver = fallback_resolver) { |
root_module->fallback_module = fallback_resolver->root_module; |
} |
predefines = initial_predefines; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
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; |
} |
|
|
|
|
|
|
|
|
void remove_include_path(string tmp) |
{ |
tmp=normalize_path(combine_path_with_cwd(tmp)); |
pike_include_path-=({tmp}); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void add_module_path(string path, string|void subpath) |
{ |
path=normalize_path(combine_path_with_cwd(path)); |
|
object s = file_stat(path); |
if(s && s->isreg) |
{ |
object fs; |
catch(fs = resolv("Filesystem.Zip")(path)); |
if(fs) add_filesystem_handler(path, fs); |
if(!subpath) subpath = "modules"; |
path = combine_path(path, subpath); |
} |
|
root_module->add_path(path); |
pike_module_path = ({ path }) + (pike_module_path - ({ path })); |
} |
|
|
|
|
|
|
|
|
void remove_module_path(string tmp) |
{ |
tmp=normalize_path(combine_path_with_cwd(tmp)); |
root_module->rem_path(tmp); |
pike_module_path -= ({ tmp }); |
} |
|
|
|
|
|
|
|
|
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; |
} |
|
|
|
|
|
|
|
|
void remove_program_path(string tmp) |
{ |
tmp=normalize_path(combine_path_with_cwd(tmp)); |
pike_program_path-=({tmp}); |
} |
|
|
|
void add_predefine (string name, mixed value) |
{ |
predefines[name] = value; |
} |
|
|
|
void remove_predefine (string name) |
{ |
m_delete (predefines, name); |
} |
|
|
mapping get_predefines() |
{ |
return predefines; |
} |
|
string evaluate_define(string def, string arguments) |
{ |
mixed val = arguments ? predefines[def+"()"] : predefines[def]; |
if( callablep(val) ) |
{ |
object C = resolv("Parser.C"); |
array args; |
if( arguments ) |
args = map( |
map(C.group(C.split(arguments))/({","}),C.simple_reconstitute), |
Builtin.string_trim); |
else |
args = ({}); |
|
val = val( @args ); |
} |
return (string)val; |
} |
|
|
|
protected mapping(string:mixed) instantiate_static_modules(object|mapping static_modules) |
{ |
mapping(string:mixed) res = ([]), joins = ([]); |
foreach(indices(static_modules), string name) { |
mixed val = static_modules[name]; |
if (!val->_module_value) |
val = val(); |
if(mixed tmp=val->_module_value) val=tmp; |
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}), 0, 0, n); |
else |
res[n] = v; |
} |
return res; |
} |
|
|
mapping get_default_module() |
{ |
resolv_debug ("%O->get_default_module()\n", this); |
|
|
|
|
|
|
|
int saved_compat_minor=compat_minor; |
int saved_compat_major=compat_major; |
compat_minor=-1; |
compat_major=-1; |
|
mixed x; |
mixed err =catch { |
if(resolv("__default") && (x=resolv("__default.all_constants"))) |
x=x(); |
}; |
|
compat_major=saved_compat_major; |
compat_minor=saved_compat_minor; |
if(err) throw(err); |
return x; |
} |
|
|
|
|
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; |
|
|
mixed static_modules = _static_modules; |
if (current_handler->get_default_module) { |
mapping(string:mixed) default_module = |
current_handler->get_default_module(); |
if (default_module) { |
static_modules = default_module["_static_modules"] || ([]); |
} |
} |
|
node = joinnode(({ |
|
([ "_static_modules" : static_modules ]), |
instantiate_static_modules(static_modules), |
|
@filter(root_module->joined_modules, |
lambda(mixed x) { |
return objectp(x) && x->is_resolv_dirnode; |
}) }), |
current_handler, |
root_module->fallback_module, |
"predef::"); |
|
return node; |
} |
|
|
mixed resolv_base(string identifier, string|void current_file, |
object|void current_handler) |
{ |
|
return get_root_module(current_handler)[identifier]; |
} |
|
|
|
mixed resolv_or_error(string identifier, string|void current_file, |
void|object current_handler) |
{ |
mixed res = resolv(identifier, current_file, current_handler); |
if(undefinedp(res)) error("Could not resolve %s.\n", identifier); |
return res; |
} |
|
|
mixed resolv(string identifier, string|void current_file, |
object|void current_handler) |
{ |
resolv_debug("resolv(%O, %O)\n",identifier, current_file); |
INC_RESOLV_MSG_DEPTH(); |
|
|
if( no_resolv[ identifier ] ) { |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug("resolv(%O, %O) => excluded\n",identifier, current_file); |
return UNDEFINED; |
} |
|
if (current_file && !stringp(current_file)) { |
error("resolv(%O, %O, %O): current_file is not a string!\n", |
identifier, current_file, current_handler); |
} |
|
array(string) tmp = identifier/"::"; |
mixed ret; |
if (sizeof(tmp) > 1) { |
string scope = tmp[0]; |
tmp = tmp[1]/"."; |
switch(scope) { |
case "predef": |
ret = all_constants(); |
break; |
default: |
if (sscanf(scope, "%d.%d%*s", int major, int minor) == 3) { |
|
ret = get_compilation_handler(major, minor); |
if (ret) { |
mixed mod = ret->get_default_module(); |
if (mod && !undefinedp(mod = mod[tmp[0]])) { |
ret = mod; |
} else { |
ret = ret->resolv(tmp[0]); |
} |
tmp = tmp[1..]; |
break; |
} |
} |
error("resolv(%O, %O, %O): Unsupported scope: %O!\n", |
identifier, current_file, current_handler, scope); |
} |
} else { |
tmp = identifier/"."; |
ret = resolv_base(tmp[0], current_file, current_handler); |
tmp = tmp[1..]; |
} |
foreach(tmp,string index) { |
resolv_debug("indexing %O with %O...\n", |
ret, index); |
resolv_debug("indices(%O): %O\n", ret, indices(ret)); |
if (undefinedp(ret)) break; |
ret = ret[index]; |
} |
DEC_RESOLV_MSG_DEPTH(); |
#ifdef RESOLV_DEBUG |
if (undefinedp (ret)) |
resolv_debug("resolv(%O, %O) => not found\n",identifier, current_file); |
else |
resolv_debug("resolv(%O, %O) => found %O\n",identifier, current_file, ret); |
#endif /* RESOLV_DEBUG */ |
return ret; |
} |
|
|
|
|
|
string handle_include(string f, |
string current_file, |
int local_include) |
{ |
if(local_include) |
{ |
if(IS_ABSOLUTE_PATH(f)) return combine_path(f); |
return combine_path_with_cwd(dirname(current_file), f); |
} |
else |
{ |
foreach(pike_include_path, string path) |
{ |
path=combine_path(path,f); |
if(master_file_stat(fakeroot(path))) |
return path; |
} |
if (fallback_resolver) { |
return fallback_resolver->handle_include(f, current_file, |
local_include); |
} |
} |
|
return 0; |
} |
|
|
string read_include(string f) |
{ |
AUTORELOAD_CHECK_FILE(f); |
if (array|object err = catch { |
return master_read_file (f); |
}) |
compile_cb_rethrow (err); |
} |
|
protected string _sprintf(int t) |
{ |
return t=='O' && sprintf("CompatResolver(%O)",ver); |
} |
} |
|
inherit CompatResolver; |
|
|
|
string _pike_file_name; |
string _master_file_name; |
|
|
private int(0..1) _async=0; |
|
|
|
int(0..1) asyncp() { |
return _async; |
} |
|
#if constant(thread_create) |
|
protected object _backend_thread=this_thread(); |
|
|
|
|
object backend_thread() |
{ |
return _backend_thread; |
} |
#endif |
|
|
mapping(string:string) initial_predefines = ([]); |
|
protected mixed main_resolv(string sym, CompatResolver|void resolver) { |
mixed v = (resolver||this)->resolv(sym); |
if(!v) |
error("Could not resolve %s. " |
"(Perhaps the installed pike tree has been moved.)\n", sym); |
return v; |
}; |
|
|
|
|
void _main(array(string(0..255)) orig_argv) |
{ |
array(string) argv=copy_value(orig_argv); |
int debug,trace,run_tool; |
object tmp; |
string postparseaction=0; |
|
predefines = initial_predefines = |
Builtin._take_over_initial_predefines(); |
_pike_file_name = orig_argv[0]; |
_master_file_name = __FILE__; |
#if constant(thread_create) |
_backend_thread = this_thread(); |
#endif |
|
#ifndef NOT_INSTALLED |
{ |
array parts = (getenv("PIKE_INCLUDE_PATH")||"")/PATH_SEPARATOR-({""}); |
int i = sizeof(parts); |
while(i) add_include_path(parts[--i]); |
|
parts = (getenv("PIKE_PROGRAM_PATH")||"")/PATH_SEPARATOR-({""}); |
i = sizeof(parts); |
while(i) add_program_path(parts[--i]); |
|
parts = (getenv("PIKE_MODULE_PATH")||"")/PATH_SEPARATOR-({""}); |
i = sizeof(parts); |
while(i) add_module_path(parts[--i]); |
} |
#endif |
|
|
string format_paths() { |
return ("master.pike...: " + (_master_file_name || __FILE__) + "\n" |
"Module path...: " + pike_module_path*"\n" |
" " + "\n" |
"Include path..: " + pike_include_path*"\n" |
" " + "\n" |
"Program path..: " + pike_program_path*"\n" |
" " + "\n"); |
}; |
|
Version cur_compat_ver; |
|
if(sizeof(argv)>1 && sizeof(argv[1]) && argv[1][0]=='-') |
{ |
array q; |
tmp = main_resolv( "Getopt" ); |
|
int NO_ARG = tmp->NO_ARG; |
int MAY_HAVE_ARG = tmp->MAY_HAVE_ARG; |
int HAS_ARG = tmp->HAS_ARG; |
|
q=tmp->find_all_options(argv,({ |
({"compat_version", HAS_ARG, ({"-V", "--compat"}), 0, 0}), |
({"version", NO_ARG, ({"-v", "--version"}), 0, 0}), |
({"dumpversion", NO_ARG, ({"--dumpversion"}), 0, 0}), |
({"help", MAY_HAVE_ARG, ({"-h", "--help"}), 0, 0}), |
({"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", MAY_HAVE_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}), |
({"show_cpp_warn", NO_ARG, ({"--show-all-cpp-warnings","--picky-cpp"}), 0, 0}), |
}), 1); |
|
|
for(int i=sizeof(q)-1; i>=0; i--) |
{ |
switch(q[i][0]) |
{ |
case "compat_version": |
sscanf(q[i][1],"%d.%d",compat_major,compat_minor); |
break; |
|
#ifdef PIKE_AUTORELOAD |
case "autoreload": |
autoreload_on++; |
break; |
#endif |
|
case "debug_without": |
|
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": |
|
no_resolv[ "Thread" ] = 1; |
add_constant( "thread_create" ); |
break; |
default: |
no_resolv[ feature ] = 1; |
break; |
} |
} |
break; |
|
case "debug": |
debug+=(int)q[i][1]; |
break; |
|
case "trace": |
trace+=(int)q[i][1]; |
break; |
|
case "modpath": |
add_module_path(q[i][1]); |
break; |
|
case "ipath": |
add_include_path(q[i][1]); |
break; |
|
case "ppath": |
add_program_path(q[i][1]); |
break; |
|
case "warnings": |
want_warnings++; |
break; |
|
case "nowarnings": |
want_warnings--; |
break; |
|
case "master": |
_master_file_name = q[i][1]; |
break; |
|
case "run_tool": |
run_tool = 1; |
break; |
|
case "show_cpp_warn": |
show_if_constant_errors = 1; |
break; |
} |
} |
|
cur_compat_ver = Version (compat_major, compat_minor); |
if (cur_compat_ver < lowestcompat) |
{ |
werror("This Pike only supports compatibility down to %s.\n", |
(string)lowestcompat); |
cur_compat_ver = lowestcompat; |
compat_major = lowestcompat->major; |
compat_minor = lowestcompat->minor; |
} |
if (compat_major != -1) { |
object compat_master = get_compat_master (compat_major, compat_minor); |
} |
|
foreach(q, array opts) |
{ |
switch(opts[0]) |
{ |
case "dumpversion": |
write("%d.%d.%d\n", __REAL_MAJOR__, __REAL_MINOR__, __REAL_BUILD__); |
exit(0); |
|
case "version": |
exit(0, string_to_utf8(version() + " Copyright © 1994-2016 Linköping University\n" |
"Pike comes with ABSOLUTELY NO WARRANTY; This is free software and you are\n" |
"welcome to redistribute it under certain conditions; read the files\n" |
"COPYING and COPYRIGHT in the Pike distribution for more details.\n")); |
|
case "help": |
exit( 0, main_resolv("Tools.MasterHelp")->do_help(opts[1]) ); |
|
case "features": |
postparseaction="features"; |
break; |
|
case "info": |
postparseaction="info"; |
break; |
|
case "showpaths": |
if( stringp(opts[1]) ) |
{ |
switch(opts[1]) |
{ |
case "master": |
write( (_master_file_name || __FILE__)+"\n" ); |
break; |
|
case "module": |
write( (pike_module_path * ":")+"\n" ); |
break; |
|
case "include": |
write( (pike_include_path * ":")+"\n" ); |
break; |
|
case "program": |
write( (pike_program_path * ":")+"\n" ); |
break; |
|
default: |
exit(1, "Unknown path type %s\n", opts[1]); |
} |
exit(0); |
} |
|
exit(0, format_paths()); |
|
case "execute": |
main_resolv( "Gmp.bignum" ); |
argv = tmp->get_args(argv,1); |
|
program prog; |
mixed compile_err = catch {; |
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; |
prog = compile_string( |
"#define NOT(X) !(X)\n" |
"mixed run(int argc, array(string) argv){" + code + ";}"); |
} |
}; |
|
if (compile_err) { |
if (compile_err->is_cpp_or_compilation_error) { |
|
|
exit (20, call_describe_error (compile_err)); |
} |
else throw (compile_err); |
} |
|
#if constant(_debug) |
if(debug) _debug(debug); |
#endif |
if(trace) trace = predef::trace(trace); |
mixed ret; |
mixed err = catch { |
|
|
|
|
ret = prog()->run(sizeof(argv),argv); |
}; |
predef::trace(trace); |
if (err) { |
handle_error (err); |
ret = 10; |
} |
if(stringp(ret)) { |
write(ret); |
if(ret[-1]!='\n') write("\n"); |
} |
if(!intp(ret) || ret<0) ret=0; |
exit(ret); |
|
case "preprocess": |
main_resolv( "Gmp.bignum" ); |
write(cpp(master_read_file(opts[1]),opts[1])); |
exit(0); |
|
case "compiler_trace": |
function(int:void) compiler_trace = |
main_resolv("Debug.compiler_trace"); |
if (compiler_trace) { |
compiler_trace(1); |
} |
break; |
|
case "assembler_debug": |
function(int:void) assembler_debug = |
main_resolv("Debug.assembler_debug"); |
if (assembler_debug) { |
assembler_debug((int)opts[1]); |
} |
break; |
|
case "optimizer_debug": |
function(int:void) optimizer_debug = |
main_resolv("Debug.optimizer_debug"); |
if (optimizer_debug) { |
optimizer_debug((int)opts[1]); |
} |
break; |
} |
} |
|
argv = tmp->get_args(argv,1); |
} |
else |
cur_compat_ver = Version (compat_major, compat_minor); |
|
switch (postparseaction) |
{ |
case "features": |
write( main_resolv( "Tools.Install.features" )()*"\n"+"\n" ); |
exit(0); |
|
case "info": |
write("Software......Pike\n" |
"Version......."+version()+"\n" |
"WWW...........http://pike.lysator.liu.se/\n" |
"\n" |
"pike binary..."+_pike_file_name+"\n"+ |
format_paths() + "\n" |
"Features......"+ |
main_resolv( "Tools.Install.features" )()*"\n "+ |
"\n"); |
exit(0); |
} |
|
main_resolv( "Gmp.bignum" ); |
|
if(sizeof(argv)==1) |
{ |
if(run_tool) { |
werror("Pike -x specificed without tool name.\n" |
"Available tools:\n"); |
mapping t = ([]); |
int i; |
object ts = main_resolv("Tools.Standalone", |
get_compilation_handler(compat_major, |
compat_minor)); |
foreach (indices(ts), string s) { |
mixed val = ts[s]; |
if (programp (val)) { |
object o = val(); |
if(!o->main || !o->description) continue; |
t[s] = o->description; |
i = max(i, sizeof(s)); |
} |
} |
foreach(sort(indices(t)), string s) |
werror(" %-"+i+"s %s\n", s, t[s]); |
exit(1); |
} |
main_resolv("Tools.Hilfe", |
get_compilation_handler(compat_major, |
compat_minor))->StdinHilfe(); |
exit(0); |
} |
else |
argv=argv[1..]; |
|
program prog; |
|
if(run_tool) { |
mixed err = catch { |
prog = main_resolv("Tools.Standalone." + argv[0], |
get_compilation_handler(compat_major, compat_minor)); |
}; |
|
if (err) |
exit(1, "Pike: Failed to load tool %s:\n" |
"%s\n", argv[0], |
stringp(err[0])?err[0]:call_describe_backtrace(err)); |
|
argv[0] = search(programs, prog) || argv[0]; |
} else { |
argv[0]=combine_path_with_cwd(argv[0]); |
|
mixed err = catch { |
prog=(program)argv[0]; |
}; |
|
if (err) { |
string fn = argv[0]; |
if( !file_stat(fn) ) |
{ |
if( file_stat(fn+".pike") ) |
fn += ".pike"; |
else |
exit(1, "Could not find file %O.\n", fn); |
} |
if( !file_stat(fn)->isreg ) |
exit(1, "File %O is not a regular file.\n", fn); |
if( !master_read_file(fn) ) |
exit(1, "File %O is not readable. %m.\n", fn); |
if (objectp (err) && err->is_cpp_or_compilation_error) |
exit(1, "Pike: Failed to compile script.\n"); |
else |
exit(1, "Pike: Failed to compile script:\n" |
"%s", call_describe_backtrace(err)); |
} |
|
|
|
|
programs[argv[0]] = no_value; |
} |
|
programs["/main"] = prog; |
|
|
if(!prog) |
error("Pike: Couldn't find script to execute\n(%O)\n", argv[0]); |
|
#if constant(_debug) |
if(debug) _debug(debug); |
#endif |
if(trace) trace = predef::trace(trace); |
mixed ret; |
mixed err = catch { |
|
|
|
|
|
object script; |
script=prog(argv); |
|
if(!script->main) |
error("Error: %s has no main().\n", argv[0]); |
if (cur_compat_ver <= Version (8, 0)) |
ret = script->main(sizeof(argv),argv); |
else |
{ |
mixed first_arg = __get_first_arg_type(_typeof(script->main)); |
|
if( first_arg && (typeof(argv) <= first_arg) ) { |
|
ret=script->main(argv); |
} else |
ret=script->main(sizeof(argv),argv); |
} |
}; |
|
trace = predef::trace(trace); |
if (err) { |
handle_error (err); |
ret = 10; |
} |
if(!intp(ret)) |
exit(10, "Error: Non-integer value %O returned from main.\n", ret); |
|
if(ret >=0) exit([int]ret); |
_async=1; |
|
|
trace = predef::trace(trace); |
while(1) |
{ |
mixed err=catch |
{ |
while(1) |
Builtin.__backend(3600.0); |
}; |
master()->handle_error(err); |
} |
} |
|
#if constant(thread_local) |
object inhibit_compile_errors = thread_local(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void set_inhibit_compile_errors(mixed behaviour) |
{ |
inhibit_compile_errors->set(behaviour); |
} |
|
|
|
|
|
|
|
mixed get_inhibit_compile_errors() |
{ |
return inhibit_compile_errors->get(); |
} |
#else /* !constant(thread_local) */ |
mixed inhibit_compile_errors; |
|
void set_inhibit_compile_errors(mixed f) |
{ |
inhibit_compile_errors=f; |
} |
|
mixed get_inhibit_compile_errors() |
{ |
return inhibit_compile_errors; |
} |
#endif /* constant(thread_local) */ |
|
protected private function(string:string) _trim_file_name_cb=0; |
string trim_file_name(string s) |
{ |
#ifdef PIKE_MODULE_RELOC |
s = relocate_module(s); |
#endif |
if(getenv("LONG_PIKE_ERRORS")) return s; |
if(getenv("SHORT_PIKE_ERRORS")) return BASENAME(s); |
|
if (_trim_file_name_cb) return _trim_file_name_cb(s); |
|
|
|
|
catch { |
string cwd=getcwd(); |
if (sizeof(cwd) && (cwd[-1] != '/')) { |
cwd += "/"; |
} |
if(has_prefix (s, cwd)) return s[sizeof(cwd)..]; |
}; |
return s; |
} |
|
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; |
} |
|
|
|
|
|
|
|
|
|
void compile_error(string file,int line,string err) |
{ |
mixed val; |
if(! (val = get_inhibit_compile_errors() )) |
{ |
werror( "%s:%s:%s\n",trim_file_name(file), |
line?(string)line:"-",narrowify_string(err) ); |
} |
else if(objectp(val) || |
programp(val) || |
functionp(val)) |
{ |
if (objectp(val) && val->compile_error) { |
val->compile_error(file, line, err); |
} else if (callablep(val)) { |
val(file, line, err); |
} |
} |
} |
|
|
|
|
|
|
|
|
|
void compile_warning(string file,int line,string err) |
{ |
mixed val; |
|
if(!(val = get_inhibit_compile_errors() )) |
{ |
if(want_warnings) |
werror( "%s:%s: Warning: %s\n",trim_file_name(file), |
line?(string)line:"-",narrowify_string(err) ); |
} |
else if (objectp(val) && val->compile_warning) { |
([function(string,int,string:void)]([object]val) |
->compile_warning)(file, line, err); |
} |
} |
|
|
|
|
|
|
|
|
|
int compile_exception (array|object trace) |
{ |
if (objectp (trace) && ([object]trace)->is_cpp_or_compilation_error) |
|
|
|
return 0; |
if (mixed val = get_inhibit_compile_errors()) { |
if (objectp(val) && ([object]val)->compile_exception) |
return ([function(object:int)]([object]val) |
->compile_exception)([object]trace); |
} |
else { |
handle_error (trace); |
return 1; |
} |
return 0; |
} |
|
|
|
|
|
|
void runtime_warning (string where, string what, mixed... args) |
{ |
if (want_warnings) |
switch (where + "." + what) { |
case "gc.bad_cycle": |
|
|
#if 0 |
|
|
werror ("GC warning: Garbing cycle where destroy() will be called " |
"in arbitrary order:\n%{ %s\n%}", |
sprintf("%O", args[0][*])); |
#endif |
break; |
|
default: |
werror ("%s warning: %s %O\n", capitalize (where), what, args); |
} |
} |
|
|
protected object Charset; |
|
|
|
string decode_charset(string data, string charset) |
{ |
if (!Charset) { |
Charset = [object]resolv("Charset"); |
if (!Charset) |
compile_cb_error("Cannot handle charset - no Charset module found."); |
} |
|
if (mixed err = catch { |
object decoder = ([function(string:object)]Charset.decoder)(charset); |
return ([function(void:string)]([function(string:object)]decoder-> |
feed)(data)->drain)(); |
}) |
compile_cb_rethrow (err); |
} |
|
|
class Describer |
{ |
int clipped=0; |
int canclip=0; |
mapping(mixed:int|string) ident = ([]); |
int identcount = 0; |
|
void identify_parts (mixed stuff) |
{ |
|
|
|
array identify_stack = ({stuff}); |
while (sizeof (identify_stack)) { |
stuff = identify_stack[-1]; |
identify_stack = identify_stack[..<1]; |
if (!intp(ident[stuff])) continue; |
if (objectp (stuff) || functionp (stuff) || programp (stuff)) |
ident[stuff]++; |
else if (arrayp (stuff)) { |
if (!ident[stuff]++) |
identify_stack += stuff; |
} |
else if (multisetp (stuff)) { |
if (!ident[stuff]++) |
identify_stack += indices([multiset]stuff); |
} |
else if (mappingp (stuff)) { |
if (!ident[stuff]++) |
identify_stack += indices([mapping]stuff) + values([mapping]stuff); |
} |
} |
} |
|
string describe_string (string m, int maxlen) |
{ |
canclip++; |
if(sizeof(m) < maxlen) |
{ |
string t = sprintf("%q", m); |
if (sizeof(t) < (maxlen + 2)) |
return t; |
t = 0; |
} |
clipped++; |
if(maxlen>10) { |
int h = (3*maxlen)/4; |
return sprintf("%q+[%d]+%q", |
m[..h-5], |
sizeof(m)-(maxlen-8), |
m[sizeof(m) - (maxlen - (h + 4))..]); |
} |
|
return "string["+sizeof(m)+"]"; |
} |
|
string describe_array (array m, int maxlen) |
{ |
if(!sizeof(m)) return "({})"; |
else { |
if(maxlen<5) |
{ |
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)+"]"; |
} |
|
string describe (mixed m, int maxlen) |
{ |
catch { |
if (stringp (ident[m])) return [string]ident[m]; |
else if (intp (ident[m]) && ident[m] > 1) |
ident[m] = "@" + identcount++; |
}; |
|
string res; |
if (catch (res=sprintf("%t",m))) |
res = "object"; |
switch(res) |
{ |
case "int": |
if (!m && undefinedp (m) == 1) |
return "UNDEFINED"; |
case "float": |
return (string)m; |
case "string": |
return describe_string ([string]m, maxlen); |
case "array": |
res = describe_array ([array]m, maxlen); |
break; |
case "mapping": |
res = describe_mapping ([mapping]m, maxlen); |
break; |
case "multiset": |
res = describe_multiset ([multiset]m, maxlen); |
break; |
case "function": |
if (string tmp=describe_function([function]m)) res = tmp; |
break; |
case "program": |
if(string tmp=describe_program([program]m)) res = tmp; |
break; |
default: |
|
if (catch { |
if(string tmp=sprintf("%O", m)) res = tmp; |
}) { |
|
res = sprintf("Instance of %O", _typeof(m)); |
} |
break; |
} |
|
|
res = narrowify_string(res); |
if (stringp(ident[m])) |
return ident[m] + "=" + res; |
return res; |
} |
|
string 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; |
|
while(1) |
{ |
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]=describe(x[e],len); |
isclipped[e]=clipped; |
clippable[e]=canclip; |
} |
|
while(1) |
{ |
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; |
|
for(int e=0;e<clip;e++) |
{ |
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; |
} |
|
newlen=num_large ? (maxlen-smallsize)/num_large : 0; |
|
if(newlen<8 || newlen >= last_newlen) break; |
last_newlen=newlen; |
} |
|
if(newlen < 8 && clip) |
{ |