|
|
|
|
|
|
|
|
|
|
|
#pike __REAL_VERSION__ |
#define PIKE_AUTORELOAD |
|
|
#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; |
|
#ifndef PIKE_WARNINGS |
#define PIKE_WARNINGS 0 |
#endif /* PIKE_WARNINGS */ |
|
|
|
|
|
#ifdef PIKE_FAKEROOT |
object o; |
string fakeroot(string s) |
{ |
string tmp1=combine_path_with_cwd(s); |
#ifdef PIKE_FAKEROOT_OMIT |
foreach(PIKE_FAKEROOT_OMIT/":", string x) |
if(glob(x,tmp1)) |
return s; |
#endif |
return PIKE_FAKEROOT+tmp1; |
} |
#else |
#define fakeroot(X) X |
#endif |
|
|
|
|
|
|
|
int is_absolute_path(string p) |
{ |
#ifdef __NT__ |
p=replace(p,"\\","/"); |
if(sscanf(p,"%[a-zA-Z]:%*c",string s)==2 && sizeof(s)==1) |
return 1; |
#define IS_ABSOLUTE_PATH is_absolute_path |
#else |
#define IS_ABSOLUTE_PATH(X) ((X)[0]=='/') |
#endif |
return p[0]=='/'; |
} |
|
|
|
|
|
|
|
|
array(string) explode_path(string p) |
{ |
#ifdef __NT__ |
p=replace(p,"\\","/"); |
#define EXPLODE_PATH(X) (replace((X),"\\","/")/"/") |
#else |
#define EXPLODE_PATH(X) ((X)/"/") |
#endif |
return p/"/"; |
} |
|
|
|
|
|
|
string dirname(string x) |
{ |
array(string) tmp=EXPLODE_PATH(x); |
return tmp[..sizeof(tmp)-2]*"/"; |
} |
|
|
|
|
|
|
string basename(string x) |
{ |
array(string) tmp=EXPLODE_PATH(x); |
return tmp[-1]; |
} |
#define DIRNAME dirname |
#define BASENAME(X) (EXPLODE_PATH(X)[-1]) |
|
#define GETCWD_CACHE |
#define FILE_STAT_CACHE |
|
#define UNDEFINED (([])[0]) |
#define error(X) throw( ({ (X), backtrace()/*[0..sizeof(backtrace())-2]*/ }) ) |
|
int want_warnings = PIKE_WARNINGS; |
|
#ifdef PIKE_AUTORELOAD |
|
int autoreload_on; |
int newest; |
|
#define AUTORELOAD_CHECK_FILE(X) \ |
if(autoreload_on) if(mixed fnord=master_file_stat(X)) if(fnord[3]>newest) newest=fnord[3]; |
|
#define AUTORELOAD_BEGIN() \ |
int ___newest=newest; \ |
newest=0 |
|
|
#define AUTORELOAD_FINISH(VAR, CACHE, FILE) \ |
if(autoreload_on) { \ |
if(CACHE [ FILE ] && newest <= load_time[FILE]) { \ |
VAR = CACHE [ FILE ]; \ |
} \ |
} \ |
load_time[FILE]=time(); \ |
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 |
|
int compat_major=-1; |
int compat_minor=-1; |
|
|
|
|
|
|
|
|
|
|
program compile_string(string source, void|string filename, |
object|void handler) |
{ |
return compile(cpp(source, filename||"-", 1, handler, |
compat_major, compat_minor), |
handler, |
compat_major, |
compat_minor); |
} |
|
|
string master_read_file(string file) |
{ |
object o=_static_modules.files()->Fd(); |
if(o->open(fakeroot(file),"r")) |
return o->read(); |
return 0; |
} |
|
#ifdef GETCWD_CACHE |
string current_path; |
int cd(string s) |
{ |
current_path=0; |
return predef::cd(s); |
} |
|
string getcwd() |
{ |
return current_path || (current_path=predef::getcwd()); |
} |
#endif |
|
string combine_path_with_cwd(string path) |
{ |
return combine_path(IS_ABSOLUTE_PATH(path)?"/":getcwd(),path); |
} |
|
#define Stat _static_modules.files.Stat |
#ifdef FILE_STAT_CACHE |
|
#define FILE_STAT_CACHE_TIME 20 |
|
int invalidate_time; |
mapping(string:multiset(string)) dir_cache = ([]); |
|
Stat master_file_stat(string x) |
{ |
string file, dir=combine_path_with_cwd(x); |
|
file=BASENAME(dir); |
dir=DIRNAME(dir); |
|
multiset(string) d; |
if(time() > invalidate_time) |
{ |
dir_cache=([]); |
invalidate_time=time()+FILE_STAT_CACHE_TIME; |
} |
if(zero_type(d=dir_cache[dir])) |
{ |
if(array(string) tmp=get_dir(dir)) |
{ |
#ifdef __NT__ |
tmp=map(tmp, lower_case); |
#endif |
d=dir_cache[dir]=aggregate_multiset(@tmp); |
}else{ |
dir_cache[dir]=0; |
} |
} |
|
#ifdef __NT__ |
file=lower_case(file); |
#endif |
if(d && !d[file]) return 0; |
|
return predef::file_stat(x); |
} |
#else |
#define master_file_stat file_stat |
#endif |
|
mapping (string:string) environment=([]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string|mapping(string:string) getenv(string|void s) |
{ |
if(!s) return environment + ([]); |
return environment[s]; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
program compile_file(string filename, |
object|void handler, |
void|program p, |
void|object o) |
{ |
AUTORELOAD_CHECK_FILE(filename); |
return compile(cpp(master_read_file(filename), |
filename, |
1, |
handler, |
compat_major, |
compat_minor), |
handler, |
compat_major, |
compat_minor, |
p, |
o); |
} |
|
|
|
#if 0 |
variant mapping(string:string) getenv() |
{ |
return environment + ([]); |
} |
|
variant string getenv(string s) |
{ |
return environment[s]; |
} |
|
function(:mapping(string:string))|function(string:string) getenv(s) |
{ |
if(!s) return environment + ([]); |
return environment[s]; |
} |
|
mapping(string:string) getenv() | |
string getenv(string s) |
{ |
if(!s) return environment + ([]); |
return environment[s]; |
} |
#endif /* 0 */ |
|
|
|
|
|
|
|
void putenv(string varname, string value) |
{ |
environment[varname] = value; |
} |
|
|
string normalize_path( string X ) |
{ |
#ifndef __NT__ |
return X; |
#else |
return replace(X,"\\","/"); |
#endif |
} |
|
mapping (string:program) programs=(["/master":object_program(this_object())]); |
|
#define capitalize(X) (upper_case((X)[..0])+(X)[1..]) |
|
array(string) query_precompiled_names(string fname) |
{ |
|
return ({ fname + ".o" }); |
} |
|
#if constant(_static_modules.Builtin.mutex) |
#define THREADED |
object compilation_mutex = _static_modules.Builtin()->mutex(); |
#endif |
|
static program low_findprog(string pname, |
string ext, |
object|void handler, |
void|int mkobj) |
{ |
program ret; |
Stat s; |
string fname=pname+ext; |
|
#ifdef THREADED |
object key; |
|
|
|
mixed err = catch { |
key=compilation_mutex->lock(2); |
}; |
if (err) { |
werror(sprintf("low_findprog: Caught spurious error:\n" |
"%s\n", describe_backtrace(err))); |
} |
#endif |
|
#ifdef PIKE_AUTORELOAD |
if(!autoreload_on || load_time[fname]>=time()) |
#endif |
{ |
if(!zero_type (ret=programs[fname])) return ret; |
} |
|
#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[1]>=0 ) |
{ |
AUTORELOAD_BEGIN(); |
|
#ifdef PIKE_AUTORELOAD |
if (load_time[fname] > s[3]) |
if (!zero_type (ret=programs[fname])) return ret; |
#endif |
|
switch(ext) |
{ |
case "": |
case ".pike": |
foreach(query_precompiled_names(fname), string oname) { |
if(Stat s2=master_file_stat(fakeroot(oname))) |
{ |
if(s2[1]>=0 && s2[3]>=s[3]) |
{ |
mixed err=catch { |
AUTORELOAD_CHECK_FILE(oname); |
return programs[fname] = |
decode_value(master_read_file(oname), |
Codec()); |
}; |
if (handler) { |
handler->compile_warning(oname, 0, |
sprintf("Decode failed:\n" |
"\t%s", err[0])); |
} else { |
compile_warning(oname, 0, |
sprintf("Decode failed:\n" |
"\t%s", err[0])); |
} |
} else if (out_of_date_warning) { |
if (handler) { |
handler->compile_warning(oname, 0, |
"Compiled file is out of date\n"); |
} else { |
compile_warning(oname, 0, "Compiled file is out of date\n"); |
} |
} |
} |
} |
|
|
programs[fname]=ret=__empty_program(); |
if ( mixed e=catch { |
ret=compile_file(fname, |
handler, |
ret, |
mkobj? (objects[ret]=__null_program()) : 0); |
} ) |
{ |
|
ret=programs[fname]=0; |
if(arrayp(e) && sizeof(e) && e[0] == "Compilation failed.\n") |
e[1]=({}); |
throw(e); |
} |
break; |
#if constant(load_module) |
case ".so": |
if (fname == "") { |
werror(sprintf("low_find_prog(\"%s\", \"%s\") => load_module(\"\")\n" |
"%s\n", pname, ext, describe_backtrace(backtrace()))); |
} |
|
ret=load_module(fakeroot(fname)); |
#endif /* load_module */ |
} |
|
AUTORELOAD_FINISH(ret,programs,fname); |
|
|
return programs[fname]=ret; |
} |
return 0; |
} |
|
static 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; |
array(string) tmp=EXPLODE_PATH(pname); |
|
|
|
|
if(sscanf(reverse(tmp[-1]),"%s.%s",ext, nname)) |
{ |
ext="."+reverse(ext); |
tmp[-1]=reverse(nname); |
pname=tmp*"/"; |
}else{ |
ext=""; |
} |
if(IS_ABSOLUTE_PATH(pname)) |
{ |
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) |
{ |
return low_cast_to_program(pname, current_file, handler); |
} |
|
|
|
|
|
void handle_error(array(mixed)|object trace) |
{ |
if(mixed x=catch { |
werror(describe_backtrace(trace)); |
}) |
{ |
|
|
|
werror("Error in handle_error in master object:\n"); |
if(catch { |
if (catch { |
string msg = x[0]; |
array bt = x[1]; |
werror ("%s%O\nOriginal error:\n%O\n", msg, bt, trace); |
}) |
werror("%O\nOriginal error:\n%O\n",x,trace); |
}) { |
werror("sprintf() failed to write error.\n"); |
} |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
object new(string|program prog, mixed ... args) |
{ |
if(stringp(prog)) |
{ |
if(program p=cast_to_program(prog,backtrace()[-2][0])) |
return p(@args); |
else |
error(sprintf("new: failed to find program %s.\n",prog)); |
} |
return prog(@args); |
} |
|
function clone = new; |
|
|
|
|
constant master_efuns = ({ |
"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", |
"new", |
"clone", |
"normalize_path", |
"getenv", |
"putenv", |
|
#ifdef GETCWD_CACHE |
"cd", |
"getcwd", |
#endif |
}); |
|
|
|
void create() |
{ |
object o = this_object(); |
|
foreach(master_efuns, string e) { |
if (o[e]) { |
add_constant(e, o[e]); |
} else { |
throw(({ sprintf("Function %O is missing from master.pike.\n", e), |
backtrace() })); |
} |
} |
|
add_constant("strlen", sizeof); |
add_constant("UNDEFINED", UNDEFINED); |
add_constant("write", _static_modules.files()->_stdout->write); |
|
#define CO(X) add_constant(#X,_static_modules.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 |
} |
|
|
|
|
|
|
|
|
|
|
|
program handle_inherit(string pname, string current_file, object|void handler) |
{ |
return cast_to_program(pname, current_file, handler); |
} |
|
mapping (program:object) objects=([object_program(this_object()):this_object()]); |
|
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(!(o=objects[p])) o=objects[p]=p(); |
return o; |
} |
|
|
|
|
|
object cast_to_object(string oname, string current_file) |
{ |
if(object o=low_cast_to_object(oname, current_file)) |
return o; |
error("Cast '"+oname+"' to object failed"+ |
((current_file && current_file!="-")?sprintf(" for '%s'",current_file):"")+".\n"); |
return 0; |
} |
|
class dirnode(string dirname, object|void handler) |
{ |
constant is_resolv_dirnode = 1; |
mixed module=module_checker(); |
mapping(string:mixed) cache=([]); |
array(string) files; |
|
class module_checker |
{ |
int `!() |
{ |
module=0; |
if(module=findmodule(dirname+"/module", handler)) |
if(mixed tmp=module->_module_value) |
module=tmp; |
return !module; |
} |
|
mixed `[](string index) { if(module) return module[index]; } |
array(string) _indices() { if(module) return indices(module); } |
array _values() { if(module) return values(module); } |
} |
|
static mixed ind(string index) |
{ |
if(module) |
{ |
object o; |
if(!zero_type(o=module[index])) |
{ |
|
return o; |
} |
} |
|
if( !files ) |
files = get_dir(fakeroot(dirname)); |
|
int ret; |
foreach( files, string s ) |
{ |
if( search(s, index)!=-1 || search(index,s)!=-1 ) |
{ |
ret=1; |
break; |
} |
} |
if(!ret) |
return UNDEFINED; |
index = dirname+"/"+index; |
if(object o=findmodule(index, handler)) |
{ |
if(mixed tmp=o->_module_value) o=tmp; |
return o; |
} |
if (program p=cast_to_program( index, 0, handler )) |
{ |
|
return p; |
} |
|
return UNDEFINED; |
} |
|
mixed `[](string index) |
{ |
mixed ret; |
|
if(!zero_type(ret=cache[index])) |
{ |
|
|
|
if(!intp (ret) || ret) return ret; |
return UNDEFINED; |
} |
return cache[index]=ind(index); |
} |
|
static int _cache_full; |
void fill_cache() |
{ |
#ifdef RESOLV_DEBUG |
werror(describe_backtrace(({ sprintf("Filling cache in dirnode %O\n", |
dirname), |
backtrace() }))); |
#endif /* RESOLV_DEBUG */ |
if (_cache_full) { |
return; |
} |
|
if (module) { |
foreach(indices(module), string index) { |
cache[index] = module[index]; |
} |
} |
|
if( !files ) |
files = get_dir(fakeroot(dirname)); |
foreach(files, string fname) { |
mixed err = catch { |
if (((< ".pike", ".pmod" >)[fname[sizeof(fname)-5..]]) && |
!zero_type(`[](fname[..sizeof(fname)-6]))) { |
continue; |
} else if ((fname[sizeof(fname)-3..] == ".so") && |
!zero_type(`[](fname[..sizeof(fname)-4]))) { |
continue; |
} |
}; |
if (err) { |
compile_warning(dirname+"."+fname, 0, |
sprintf("Compilation failed:\n" |
"%s\n", |
describe_backtrace(err))); |
} |
} |
_cache_full = 1; |
} |
array(string) _indices() |
{ |
|
fill_cache(); |
return indices(filter(cache, lambda(mixed x){ return !intp (x) || x; })); |
} |
array(mixed) _values() |
{ |
|
fill_cache(); |
return values(cache)-({0}); |
} |
|
string _sprintf(int as) |
{ |
return sprintf("master()->dirnode(%O)",dirname); |
} |
|
}; |
|
static class ZERO_TYPE {}; |
|
class joinnode |
{ |
constant is_resolv_joinnode = 1; |
array(object|mapping) joined_modules; |
mapping(string:mixed) cache=([]); |
|
string _sprintf(int as) |
{ |
return sprintf("master()->joinnode(%O)",joined_modules); |
} |
|
void create(array(object|mapping) _joined_modules) |
{ |
joined_modules = _joined_modules; |
} |
|
static mixed ind(string index) |
{ |
array(mixed) res = ({}); |
foreach(joined_modules, object|mapping o) |
{ |
mixed ret; |
if (!zero_type(ret = o[index])) |
{ |
if (objectp(ret = o[index]) && |
(ret->is_resolv_dirnode || ret->is_resolv_joinnode)) |
{ |
|
res += ({ ret }); |
} else if ( !zero_type(ret) ) { |
return (ret); |
} else { |
|
continue; |
} |
} |
} |
if (sizeof(res) > 1) |
return joinnode(res); |
else if (sizeof(res)) |
return res[0]; |
return UNDEFINED; |
} |
|
mixed `[](string index) |
{ |
mixed ret; |
if (!zero_type(ret = cache[index])) { |
if (ret != ZERO_TYPE) { |
return ret; |
} |
return UNDEFINED; |
} |
ret = ind(index); |
if (zero_type(ret)) { |
cache[index] = ZERO_TYPE; |
} else { |
cache[index] = ret; |
} |
return ret; |
} |
static int _cache_full; |
void fill_cache() |
{ |
#ifdef RESOLV_DEBUG |
werror(describe_backtrace(({ "Filling cache in joinnode\n", |
backtrace() }))); |
#endif /* RESOLV_DEBUG */ |
if (_cache_full) { |
return; |
} |
foreach(joined_modules, object|mapping|program o) { |
foreach(indices(o), string index) { |
if (zero_type(cache[index])) { |
`[](index); |
} |
} |
} |
_cache_full = 1; |
} |
array(string) _indices() |
{ |
fill_cache(); |
return indices(cache); |
} |
array(mixed) _values() |
{ |
fill_cache(); |
return values(cache); |
} |
}; |
|
|
|
mapping(string:mixed) fc=([]); |
|
object findmodule(string fullname, object|void handler) |
{ |
object o; |
if(!zero_type(o=fc[fullname])) |
{ |
|
return o; |
} |
|
if(Stat stat=master_file_stat(fakeroot(fullname+".pmod"))) |
{ |
if(stat[1]==-2) |
return fc[fullname]=dirnode(fullname+".pmod", handler); |
} |
|
if(o = low_cast_to_object(fullname+".pmod", "/.", handler)) |
return fc[fullname]=o; |
|
#if constant(load_module) |
if(master_file_stat(fakeroot(fullname+".so"))) |
return fc[fullname] = low_cast_to_object(fullname, "/.", handler); |
#endif |
|
return fc[fullname]=UNDEFINED; |
} |
|
mixed handle_import(string what, string|void current_file, object|void handler) |
{ |
array(string) tmp; |
string path; |
if(current_file) |
{ |
tmp=EXPLODE_PATH(current_file); |
tmp[-1]=what; |
path=combine_path_with_cwd( tmp*"/"); |
} |
if (handler) { |
return dirnode(path, handler); |
} |
return fc[path]=dirnode(path); |
} |
|
|
|
multiset no_resolv = (<>); |
class CompatResolver |
{ |
array(string) pike_include_path=({}); |
array(string) pike_module_path=({}); |
array(string) pike_program_path=({}); |
int want_warnings = PIKE_WARNINGS; |
string ver; |
|
void create(mixed v) |
{ |
ver=(string)v; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
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 tmp) |
{ |
tmp=normalize_path(combine_path_with_cwd(tmp)); |
pike_module_path-=({tmp}); |
pike_module_path=({tmp})+pike_module_path; |
} |
|
|
|
|
|
|
|
|
|
|
void remove_module_path(string tmp) |
{ |
tmp=normalize_path(combine_path_with_cwd(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}); |
} |
|
mapping get_default_module() |
{ |
|
|
|
|
|
|
int saved_compat_minor=compat_minor; |
int saved_compat_major=compat_major; |
compat_minor=-1; |
compat_major=-1; |
|
mixed x; |
mixed err =catch { |
if(x=resolv("__default.all_constants")) x=x(); |
}; |
|
compat_major=saved_compat_major; |
compat_minor=saved_compat_minor; |
if(err) throw(err); |
return x; |
} |
|
mixed resolv_base(string identifier, string|void current_file, |
object|void current_handler) |
{ |
array(mixed) tmp = ({}); |
string dir=current_file ? dirname(current_file) : "/"; |
|
foreach(pike_module_path, string path) |
{ |
string file=combine_path(dir, path, identifier); |
if(mixed ret=findmodule(file, current_handler)) { |
if ((objectp(ret)) && |
(ret->is_resolv_dirnode || ret->is_resolv_joinnode)) { |
if (mixed new_ret = ret->_module_value) { |
ret = new_ret; |
} |
tmp += ({ ret }); |
} else { |
if (mixed new_ret = ret->_module_value) { |
ret = new_ret; |
} |
if (!sizeof(tmp)) { |
return ret; |
} else { |
|
werror(sprintf("Ignoring file %O: %t for identifier %O\n", |
file, ret, identifier)); |
continue; |
} |
} |
} |
} |
if (sizeof(tmp)) { |
if (sizeof(tmp) == 1) { |
return(tmp[0]); |
} |
return joinnode(tmp); |
} |
return UNDEFINED; |
} |
|
mapping resolv_cache = set_weak_flag( ([]), 1 ); |
mixed resolv(string identifier, string|void current_file, |
object|void current_handler) |
{ |
|
if( no_resolv[ identifier ] ) |
return UNDEFINED; |
|
mixed ret; |
string id=identifier+":"+(current_file ? dirname(current_file) : "-"); |
if( !zero_type (ret = resolv_cache[id]) ) |
return ret == ZERO_TYPE ? UNDEFINED : resolv_cache[id]; |
array(string) tmp=identifier/"."; |
ret=resolv_base(tmp[0], current_file, current_handler); |
foreach(tmp[1..],string index) ret=ret[index]; |
resolv_cache[id] = zero_type (ret) ? ZERO_TYPE : ret; |
return ret; |
} |
|
|
|
|
|
string handle_include(string f, |
string current_file, |
int local_include) |
{ |
array(string) tmp; |
string path; |
|
if(local_include) |
{ |
tmp=EXPLODE_PATH(current_file); |
tmp[-1]=f; |
path=combine_path_with_cwd(tmp*"/"); |
} |
else |
{ |
foreach(pike_include_path, path) |
{ |
path=combine_path(path,f); |
if(master_file_stat(fakeroot(path))) |
break; |
else |
path=0; |
} |
|
} |
|
return path; |
} |
|
string read_include(string f) |
{ |
AUTORELOAD_CHECK_FILE(f) |
return master_read_file(f); |
} |
|
|
string _sprintf() |
{ |
return sprintf("CompatResolver(%s)",ver); |
} |
} |
|
inherit CompatResolver; |
|
|
|
string _pike_file_name; |
string _master_file_name; |
|
|
private int _async=0; |
|
int asyncp() { |
return _async; |
} |
|
|
|
|
#if constant(thread_create) |
|
static object _backend_thread=this_thread(); |
object backend_thread() |
{ |
return _backend_thread; |
} |
#endif |
|
|
|
|
|
|
|
void _main(array(string) orig_argv, array(string) env) |
{ |
array(string) argv=copy_value(orig_argv); |
int i,debug,trace; |
object tmp; |
string a,b; |
array q; |
string postparseaction=0; |
mixed v; |
|
_pike_file_name = orig_argv[0]; |
#if constant(thread_create) |
_backend_thread = this_thread(); |
#endif |
|
foreach(env,a) |
{ |
if(sscanf(a,"%s=%s",a,b)) |
{ |
if(a=="") |
{ |
sscanf(b,"%s=%s",a,b); |
a="="+a; |
} |
environment[a]=b; |
}else{ |
werror("Broken environment var %s\n",a); |
} |
} |
|
|
|
#ifndef NOT_INSTALLED |
q=(getenv("PIKE_INCLUDE_PATH")||"")/":"-({""}); |
for(i=sizeof(q)-1;i>=0;i--) add_include_path(q[i]); |
|
q=(getenv("PIKE_PROGRAM_PATH")||"")/":"-({""}); |
for(i=sizeof(q)-1;i>=0;i--) add_program_path(q[i]); |
|
q=(getenv("PIKE_MODULE_PATH")||"")/":"-({""}); |
for(i=sizeof(q)-1;i>=0;i--) add_module_path(q[i]); |
#endif |
|
if(sizeof(argv)>1 && sizeof(argv[1]) && argv[1][0]=='-') |
{ |
tmp=resolv("Getopt"); |
|
if (!tmp) { |
werror("master.pike: Couldn't resolv Getopt module.\n" |
"Is your PIKE_MODULE_PATH environment variable set correctly?\n"); |
exit(1); |
} |
|
q=tmp->find_all_options(argv,({ |
({"compat_version",tmp->HAS_ARG,({"-V","--compat"})}), |
({"version",tmp->NO_ARG,({"-v","--version"})}), |
({"help",tmp->NO_ARG,({"-h","--help"})}), |
({"features",tmp->NO_ARG,({"--features"})}), |
({"info",tmp->NO_ARG,({"--info"})}), |
({"execute",tmp->HAS_ARG,({"-e","--execute"})}), |
({"debug_without",tmp->HAS_ARG,({"--debug-without"})}), |
({"preprocess",tmp->HAS_ARG,({"-E","--preprocess"})}), |
({"modpath",tmp->HAS_ARG,({"-M","--module-path"})}), |
({"ipath",tmp->HAS_ARG,({"-I","--include-path"})}), |
({"ppath",tmp->HAS_ARG,({"-P","--program-path"})}), |
({"showpaths",tmp->NO_ARG,"--show-paths"}), |
({"warnings",tmp->NO_ARG,({"-w","--warnings"})}), |
({"nowarnings",tmp->NO_ARG,({"-W", "--woff", "--no-warnings"})}), |
#ifdef PIKE_AUTORELOAD |
({"autoreload",tmp->NO_ARG,({"--autoreload"})}), |
#endif |
({"master",tmp->HAS_ARG,"-m"}), |
({"compiler_trace",tmp->NO_ARG,"--compiler-trace"}), |
({"assembler_debug",tmp->MAY_HAVE_ARG,"--assembler-debug"}), |
({"optimizer_debug",tmp->MAY_HAVE_ARG,"--optimizer-debug"}), |
({"debug",tmp->MAY_HAVE_ARG,"--debug",0,1}), |
({"trace",tmp->MAY_HAVE_ARG,"--trace",0,1}), |
({"ignore",tmp->MAY_HAVE_ARG,"-Dqdatplr",0,1}), |
({"ignore",tmp->HAS_ARG,"-s"}), |
}), 1); |
|
|
for(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++; |
#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", ([])[0] ); |
break; |
default: |
no_resolv[ feature ] = 1; |
break; |
} |
} |
break; |
case "debug": |
debug+=(int)q[i][1]; |
break; |
|
#if constant(_compiler_trace) |
case "compiler_trace": |
_compiler_trace(1); |
break; |
#endif /* constant(_compiler_trace) */ |
|
#if constant(_assembler_debug) |
case "assembler_debug": |
_assembler_debug((int)q[i][1]); |
break; |
#endif /* constant(_assembler_debug) */ |
|
#if constant(_optimizer_debug) |
case "optimizer_debug": |
_optimizer_debug((int)q[i][1]); |
break; |
#endif /* constant(_optimizer_debug) */ |
|
case "trace": |
trace+=(int)q[i][1]; |
break; |
|
case "modpath": |
add_module_path(q[i][1]); |
break; |
|
case "ipath": |
add_include_path(q[i][1]); |
break; |
|
case "ppath": |
add_program_path(q[i][1]); |
break; |
|
case "warnings": |
want_warnings++; |
break; |
|
case "no-warnings": |
want_warnings--; |
break; |
|
case "master": |
_master_file_name = q[i][1]; |
break; |
} |
} |
|
foreach(q, array opts) |
{ |
switch(opts[0]) |
{ |
case "version": |
werror(version() + " Copyright © 1994-2001 Roxen Internet Software\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 DISCLAIMER in the Pike distribution for more details.\n"); |
exit(0); |
|
case "help": |
werror("Usage: pike [-driver options] script [script arguments]\n" |
"Driver options include:\n" |
" -I --include-path=<p>: Add <p> to the include path\n" |
" -M --module-path=<p> : Add <p> to the module path\n" |
" -P --program-path=<p>: Add <p> to the program path\n" |
" -e --execute=<cmd> : Run the given command instead of a script.\n" |
" -h --help : see this message\n" |
" -v --version : See what version of pike you have.\n" |
" --features : List Pike features.\n" |
" --info : List information about the Pike build and setup.\n" |
" --show-paths : See the paths and master that pike uses.\n" |
" -s# : Set stack size\n" |
" -m <file> : Use <file> as master object.\n" |
" -d -d# : Increase debug (# is how much)\n" |
" -t -t# : Increase trace level\n" |
); |
exit(0); |
|
case "features": |
postparseaction="features"; |
break; |
|
case "info": |
postparseaction="info"; |
break; |
|
case "showpaths": |
werror("Include path : " + pike_include_path*"\n" |
" " + "\n" |
"Module path : " + pike_module_path*"\n" |
" " + "\n" |
"Program path : " + pike_program_path*"\n" |
" " + "\n" |
"Master file : " + (_master_file_name || __FILE__) + "\n"); |
exit(0); |
|
case "execute": |
random_seed(time() + (getpid() * 0x11111111)); |
if(trace) predef::trace(trace); |
compile_string("mixed create(){"+opts[1]+";}")(); |
exit(0); |
|
case "preprocess": |
_static_modules.files()->_stdout->write(cpp(master_read_file(opts[1]), |
opts[1])); |
exit(0); |
} |
} |
|
argv = tmp->get_args(argv,1); |
} |
|
switch (postparseaction) |
{ |
case "features": |
v = resolv("Tools"); |
if (v) v = v["Install"]; |
if (v) v = v["features"]; |
if (!v) |
{ |
werror("Could not resolv Tools.Install.features\n"); |
exit(1); |
} |
|
_static_modules.files()->_stdout->write(v()*"\n"+"\n"); |
exit(0); |
|
case "info": |
function w=_static_modules.files()->_stdout->write; |
w("Software......Pike\n" |
"Version......."+version()+"\n" |
"WWW...........http://pike.roxen.com/\n" |
"\n"); |
|
w("pike binary..."+_pike_file_name+"\n"); |
w("master.pike..."+__FILE__+"\n"); |
|
w("Module path..." + pike_module_path*"\n" |
" " + "\n" |
"Include path.." + pike_include_path*"\n" |
" " + "\n" |
"Program path.." + pike_program_path*"\n" |
" " + "\n" |
"\n"); |
|
v = resolv("Tools"); |
if (v) v = v["Install"]; |
if (v) v = v["features"]; |
if (!v) |
{ |
werror("Could not resolv Tools.Install.features\n"); |
exit(1); |
} |
|
w("Features......"+v()*"\n "+"\n"); |
|
|
exit(0); |
} |
|
random_seed(time() + (getpid() * 0x11111111)); |
|
if(sizeof(argv)==1) |
{ |
|
tmp = resolv("Tools"); |
if (!tmp) { |
werror("Couldn't find Tools.\n"); |
exit(1); |
} |
tmp = tmp["Hilfe"]; |
if (!tmp) { |
werror("Couldn't find Hilfe.\n"); |
exit(1); |
} |
tmp->StdinHilfe(); |
exit(0); |
} else { |
argv=argv[1..]; |
} |
|
argv[0]=combine_path_with_cwd(argv[0]); |
|
program prog; |
|
mixed err = catch { |
prog=(program)argv[0]; |
}; |
|
if (err) { |
werror(sprintf("Pike: Failed to compile script:\n" |
"%s\n", stringp(err[0])?err[0]:describe_backtrace(err))); |
exit(1); |
} |
|
|
if(!prog) |
{ |
werror("Pike: Couldn't find script to execute\n(%O)\n",argv[0]); |
exit(1); |
} |
|
object script=prog(); |
|
#if constant(_debug) |
if(debug) _debug(debug); |
#endif |
if(!script->main) |
{ |
werror("Error: "+argv[0]+" has no main().\n"); |
exit(1); |
} |
|
if(trace) predef::trace(trace); |
i=script->main(sizeof(argv),argv,env); |
if(i >=0) exit(i); |
_async=1; |
|
while(1) |
{ |
mixed err=catch |
{ |
while(1) |
_static_modules.Builtin.__backend(3600.0); |
}; |
master()->handle_error(err); |
} |
} |
|
#if constant(thread_local) |
object inhibit_compile_errors = thread_local(); |
|
void set_inhibit_compile_errors(mixed f) |
{ |
inhibit_compile_errors->set(f); |
} |
|
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) */ |
|
string trim_file_name(string s) |
{ |
if(getenv("LONG_PIKE_ERRORS")) return s; |
if(getenv("SHORT_PIKE_ERRORS")) return BASENAME(s); |
|
|
|
catch { |
string cwd=getcwd(); |
if (sizeof(cwd) && (cwd[-1] != '/')) { |
cwd += "/"; |
} |
if(s[..sizeof(cwd)-1]==cwd) return s[sizeof(cwd)..]; |
}; |
return s; |
} |
|
|
|
|
|
|
|
void compile_error(string file,int line,string err) |
{ |
mixed val; |
if(! (val = get_inhibit_compile_errors() )) |
{ |
werror(sprintf("%s:%s:%s\n",trim_file_name(file), |
line?(string)line:"-",err)); |
} |
else if(objectp(val) || |
programp(val) || |
functionp(val)) |
{ |
if (objectp(val) && val->compile_error) { |
val->compile_error(file, line, err); |
} else { |
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(sprintf("%s:%s: Warning: %s\n",trim_file_name(file), |
line?(string)line:"-",err)); |
} else if (objectp(val) && val->compile_warning) { |
val->compile_warning(file, line, err); |
} |
} |
|
|
|
|
|
|
|
void runtime_warning (string where, string what, mixed... args) |
{ |
if (want_warnings) |
switch (where + "." + what) { |
case "gc.bad_cycle": |
|
|
werror ("GC warning: Garbing cycle where destroy() will be called " |
"in arbitrary order:\n%{ %s\n%}", |
map (args[0], describe_object)); |
break; |
|
default: |
werror ("%s warning: %s %O\n", capitalize (where), what, args); |
} |
} |
|
|
static mixed _charset_mod; |
|
|
|
string decode_charset(string data, string charset) |
{ |
|
|
if (!_charset_mod) { |
mixed mod = resolv("Locale"); |
|
_charset_mod = mod && mod["Charset"]; |
if (!_charset_mod) { |
compile_warning("-", 0, "No Locale.Charset module!"); |
return 0; |
} |
} |
|
object decoder; |
|
catch { |
decoder = _charset_mod->decoder(charset); |
}; |
|
if (!decoder) { |
compile_warning("-", 0, sprintf("Unknown charset %O!", charset)); |
return 0; |
} |
return decoder->feed(data)->drain(); |
} |
|
|
|
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[..sizeof (identify_stack) - 2]; |
if (arrayp (stuff)) { |
if (!ident[stuff]++) |
identify_stack += stuff; |
} |
else if (multisetp (stuff)) { |
if (!ident[stuff]++) |
identify_stack += indices (stuff); |
} |
else if (mappingp (stuff)) { |
if (!ident[stuff]++) |
identify_stack += indices (stuff) + values (stuff); |
} |
else if (objectp (stuff) || functionp (stuff) || programp (stuff)) |
ident[stuff]++; |
} |
} |
|
string describe_string (string m, int maxlen) |
{ |
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)+"]"; |
} |
} |
|
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) |
{ |
if (stringp (ident[m])) return ident[m]; |
else if (intp (ident[m]) && ident[m] > 1) |
ident[m] = "@" + identcount++; |
|
string res, typ; |
if (catch (typ=sprintf("%t",m))) |
typ = "object"; |
switch(typ) |
{ |
case "int": |
case "float": |
return (string)m; |
case "string": |
return describe_string (m, maxlen); |
case "array": |
res = describe_array (m, maxlen); |
break; |
case "mapping": |
res = describe_mapping (m, maxlen); |
break; |
case "multiset": |
res = describe_multiset (m, maxlen); |
break; |
case "function": |
if (string tmp=describe_function(m)) res = tmp; |
else res = typ; |
break; |
case "program": |
if(string tmp=describe_program(m)) res = tmp; |
else res = typ; |
break; |
default: |
if (objectp(m)) |
if(string tmp=describe_object(m)) { |
res = tmp; |
break; |
} |
res = typ; |
} |
|
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) |
{ |
clip-= (clip/4) || 1; |
if(clip > clipsuggest) clip=clipsuggest; |
|
}else{ |
len=newlen; |
done++; |
break; |
} |
} |
} |
|
return ret; |
} |
} |
|
string describe_object(object o) |
{ |
string s; |
if(!o) return 0; |
if (!catch (s = sprintf("%O",o)) && s != "object") return s; |
if(( s=describe_program(object_program(o)) )) |
return s+"()"; |
return 0; |
} |
|
string describe_program(program p) |
{ |
string s; |
if(!p) return 0; |
if(s=search(programs,p)) |
{ |
if(sscanf(reverse(s),"%s.%s",string ext,string rest) && ext=="domp") |
return EXPLODE_PATH(reverse(rest))[-1]; |
return trim_file_name(s); |
} |
|
if(mixed tmp=function_object(p)) |
{ |
if(objectp(tmp)) |
{ |
if(s=describe_program(object_program(tmp))) |
return s+"."+function_name(p); |
} |
if(programp(tmp)) |
{ |
if(s=describe_program(tmp)) |
return s+"."+function_name(p); |
} |
} |
|
|
if(s=_static_modules.Builtin()->program_defined(p)) |
return EXPLODE_PATH(s)[-1]; |
|
return 0; |
} |
|
string describe_function (function f) |
{ |
if (!f) return 0; |
|
string name; |
|
if(string s=search(programs,f)) |
{ |
if(sscanf(reverse(s),"%s.%s",string ext,string rest) && ext=="domp") |
name = EXPLODE_PATH(reverse(rest))[-1]; |
else |
name = trim_file_name(s); |
} |
else |
if (catch (name = function_name (f))) name = "function"; |
|
object o = function_object(f); |
if(objectp (o)) { |
|
string s; |
if (!catch (s = sprintf("%O",o)) && s != "object") |
return s+"->"+name; |
} |
return name; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string describe_backtrace(mixed trace, void|int linewidth) |
{ |
int e; |
string ret; |
int backtrace_len=((int)getenv("PIKE_BACKTRACE_LEN")) || bt_max_string_len; |
|
if(!linewidth) |
{ |
linewidth=99999; |
catch |
{ |
linewidth=_static_modules.files()->_stdin->tcgetattr()->columns; |
}; |
if(linewidth<10) linewidth=99999; |
} |
|
if((arrayp(trace) && sizeof(trace)==2 && stringp(trace[0])) || |
(objectp(trace) && trace->is_generic_error)) |
{ |
if (catch { |
ret = trace[0] || "No error message!\n"; |
trace = trace[1]; |
}) { |
return "Error indexing backtrace!\n"; |
} |
}else{ |
ret=""; |
} |
|
if(!arrayp(trace)) |
{ |
ret+="No backtrace.\n"; |
}else{ |
Describer desc = Describer(); |
desc->identify_parts (trace); |
|
int end = 0; |
if( (sizeof(trace)>1) && |
arrayp(trace[0]) && |
(sizeof(trace[0]) > 2) && |
(trace[0][2] == _main)) |
end = 1; |
|
mapping(string:int) prev_pos = ([]); |
array(string) frames = ({}); |
int loop_start = 0, loop_next, loops; |
|
for(e = sizeof(trace)-1; e>=end; e--) |
{ |
mixed tmp; |
string row; |
if (mixed err=catch { |
tmp = trace[e]; |
if(stringp(tmp)) |
{ |
row=tmp; |
} |
else if(arrayp(tmp)) |
{ |
string pos; |
if(sizeof(tmp)>=2 && stringp(tmp[0])) { |
if (intp(tmp[1])) { |
|
string exact_pos = tmp[0] + ":" + tmp[1]; |
int dup_frame; |
if (!zero_type (dup_frame = prev_pos[exact_pos])) { |
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[exact_pos] = sizeof (frames); |
|
pos=trim_file_name(tmp[0])+":"+tmp[1]; |
} else { |
pos = sprintf("%s:Bad line %t", trim_file_name(tmp[0]), tmp[1]); |
} |
}else{ |
mixed desc="Unknown program"; |
if(sizeof(tmp)>=3 && functionp(tmp[2])) |
{ |
catch |
{ |
if(mixed tmp=function_object(tmp[2])) |
if(tmp=object_program(tmp)) |
if(tmp=describe_program(tmp)) |
desc=tmp; |
}; |
} |
pos=desc; |
} |
|
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; |
} |
|
string data; |
|
if(sizeof(tmp)>=3) |
{ |
if(functionp(tmp[2])) { |
data = describe_function (tmp[2]); |
} |
else if (stringp(tmp[2])) { |
data= tmp[2]; |
} else |
data ="unknown function"; |
|
data+="("+ |
desc->describe_comma_list(tmp[3..], backtrace_len)+ |
")"; |
|
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)); |
} |
} else { |
row = pos; |
} |
} |
else |
{ |
if (tmp) { |
if (catch (row = sprintf("%O", tmp))) |
row = describe_program(object_program(tmp)) + " with broken _sprintf()"; |
} else { |
row = "Destructed object"; |
} |
} |
}) { |
row = sprintf("Error indexing backtrace line %d: %s (%O)!", e, err[0], err[1]); |
} |
frames += ({row + "\n"}); |
} |
|
if (loop_start) { |
|
|
array(string) 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; |
} |
|
ret += frames * ""; |
} |
|
return ret || "No backtrace!\n";; |
} |
|
|
|
|
|
|
|
|
|
|
string describe_error (mixed trace) |
{ |
if((arrayp(trace) && sizeof(trace)==2 && stringp(trace[0])) || |
(objectp(trace) && trace->is_generic_error)) |
{ |
if (catch { |
return trace[0] || "No error message.\n"; |
}) { |
return "Error indexing backtrace!\n"; |
} |
} |
return sprintf ("Backtrace is of unknown type %t!\n", trace); |
} |
|
|
class Codec |
{ |
mapping f=all_constants(); |
|
string nameof(mixed x) |
{ |
if(mixed tmp=search(f,x)) |
return "efun:"+tmp; |
|
if (programp(x)) { |
if(mixed tmp=search(programs,x)) |
return tmp; |
|
if(mixed tmp=search(values(_static_modules), x)) |
return "_static_modules."+(indices(_static_modules)[tmp]); |
} |
else if (objectp(x)) |
if(mixed tmp=search(objects,x)) |
if(tmp=search(programs,tmp)) |
return tmp; |
|
return ([])[0]; |
} |
|
function functionof(string x) |
{ |
if(sscanf(x,"efun:%s",x)) return f[x]; |
if(sscanf(x,"resolv:%s",x)) return resolv(x); |
return 0; |
} |
|
object objectof(string x) |
{ |
if(sscanf(x,"efun:%s",x)) return f[x]; |
if(sscanf(x,"resolv:%s",x)) return resolv(x); |
return cast_to_object(x,0); |
} |
|
program programof(string x) |
{ |
if(sscanf(x,"efun:%s",x)) return f[x]; |
if(sscanf(x,"resolv:%s",x)) return resolv(x); |
return cast_to_program(x,0); |
} |
|
mixed encode_object(object x) |
{ |
if(x->_encode) return x->_encode(); |
error("Cannot encode objects yet.\n"); |
} |
|
|
mixed decode_object(object o, mixed data) |
{ |
o->_decode(data); |
} |
} |
|
|
class Version |
{ |
int major; |
int minor; |
void create(int maj, int min) |
{ |
major=maj; |
minor=min; |
} |
|
#define CMP(X) ((major - (X)->major) || (minor - (X)->minor)) |
|
int `<(Version v) { return CMP(v) < 0; } |
int `>(Version v) { return CMP(v) > 0; } |
int `==(Version v) { return CMP(v)== 0; } |
int _hash() { return major * 4711 + minor ; } |
|
string _sprintf() { return sprintf("%d.%d",major,minor); } |
mixed cast(string type) |
{ |
switch(type) |
{ |
case "string": |
return sprintf("%d.%d",major,minor); |
} |
} |
} |
|
Version currentversion=Version(__MAJOR__,__MINOR__); |
mapping(Version:CompatResolver) compat_handler_cache=set_weak_flag( ([]), 1); |
|
CompatResolver get_compilation_handler(int major, int minor) |
{ |
CompatResolver ret; |
|
Version v=Version(major,minor); |
|
if(v > currentversion) |
{ |
|
return 0; |
} |
|
if(!zero_type(ret=compat_handler_cache[v])) return ret; |
|
array(Version) available=({}); |
|
#if "¤share_prefix¤"[0]!='¤' |
foreach(get_dir("¤share_prefix¤"), string ver) |
{ |
if(sscanf(ver,"%d.%d",int maj, int min)) |
{ |
Version x=Version(maj, min) ; |
if(x >= v) |
available|=({ x }); |
} |
} |
#endif |
|
#if "¤lib_prefix¤"[0]!='¤' |
foreach(get_dir("¤lib_prefix¤"), string ver) |
{ |
if(sscanf(ver,"%d.%d",int maj, int min)) |
{ |
Version x=Version(maj, min) ; |
if(x >= v) |
available|=({ x }); |
} |
} |
#endif |
|
sort(available); |
|
#ifndef RESOLVER_HACK |
|
* version-specific stuff in the CompatResolver. |
* As long as all the compatibility is done in the |
* module dierctories, RESOLVER_HACK can be undefined |
*/ |
|
|
if(!sizeof(available)) |
{ |
compat_handler_cache[v]=0; |
return 0; |
} |
|
|
if(ret=compat_handler_cache[available[0]]) |
return compat_handler_cache[v]=ret; |
#endif |
|
ret=CompatResolver(v); |
|
ret->pike_module_path=pike_module_path; |
ret->pike_include_path=pike_include_path; |
|
foreach(reverse(available), Version tmp) |
{ |
string base; |
#if "¤lib_prefix¤"[0]!='¤' |
base=combine_path("¤lib_prefix¤",sprintf("%s",tmp)); |
ret->add_module_path(combine_path(base,"modules")); |
ret->add_include_path(combine_path(base,"include")); |
#endif |
|
#if "¤share_prefix¤"[0]!='¤' |
base=combine_path("¤share_prefix¤",sprintf("%s",tmp)); |
ret->add_module_path(combine_path(base,"modules")); |
ret->add_include_path(combine_path(base,"include")); |
#endif |
} |
|
if( v <= Version(0,6)) |
ret->pike_module_path+=({"."}); |
|
compat_handler_cache[v] = ret; |
|
#ifndef RESOLVER_HACK |
compat_handler_cache[available[0]] = ret; |
#endif |
|
return ret; |
} |
|
string _sprintf() |
{ |
return "master()"; |
} |
|
|