|
|
|
|
|
|
|
|
|
|
#pike __REAL_VERSION__ |
|
|
|
#if "¤/" != "\244/" |
#error "master.pike.in is corrupted." |
#endif |
|
|
|
#define PIKE_AUTORELOAD |
#define GETCWD_CACHE |
#define FILE_STAT_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__) |
#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; |
|
|
|
|
|
private constant Builtin = _static_modules.Builtin; |
private constant Files = _static_modules.___files; |
|
#define Stat Files.Stat |
#define capitalize(X) (upper_case((X)[..0])+(X)[1..]) |
#define write(X ...) (Files()->_stdout->write(X)) |
#define trim_all_whites(X) (Builtin()->string_trim_all_whites (X)) |
|
#ifdef RESOLV_DEBUG |
|
#if constant (thread_local) |
static object resolv_msg_depth = thread_local(); |
|
#define GET_RESOLV_MSG_DEPTH (resolv_msg_depth && resolv_msg_depth->get()) |
#define INC_RESOLV_MSG_DEPTH() (resolv_msg_depth && resolv_msg_depth->set (resolv_msg_depth->get() + 1)) |
#define DEC_RESOLV_MSG_DEPTH() (resolv_msg_depth && resolv_msg_depth->set (resolv_msg_depth->get() - 1)) |
#else |
static int resolv_msg_depth; |
#define GET_RESOLV_MSG_DEPTH resolv_msg_depth |
#define INC_RESOLV_MSG_DEPTH() (++resolv_msg_depth) |
#define DEC_RESOLV_MSG_DEPTH() (--resolv_msg_depth) |
#endif |
|
void resolv_debug (string fmt, mixed... args) |
{ |
string pad = " " * GET_RESOLV_MSG_DEPTH; |
if (sizeof (args)) fmt = sprintf (fmt, @args); |
if (fmt[-1] == '\n') |
fmt = pad + replace (fmt[..sizeof (fmt) - 2], "\n", "\n" + pad) + "\n"; |
else |
fmt = pad + replace (fmt, "\n", "\n" + pad); |
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 |
|
|
|
|
void error(string f, mixed ... args) { |
array b = backtrace(); |
if (sizeof(args)) f = sprintf(f, @args); |
throw( ({ f, b[..sizeof(b)-2] }) ); |
} |
|
|
#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 |
#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) has_prefix((X),"/") |
#endif |
return has_prefix(p,"/"); |
#endif |
} |
|
#ifdef __NT__ |
#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[..sizeof(p)-colon-1] }) + explode_path(p[sizeof(p)-colon..]); |
array(string) r = p/"/"; |
return replace(r[..sizeof(r)-2], "", "/")+r[sizeof(r)-1..]; |
#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[..sizeof(tmp2)-2]*"/"; |
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[..sizeof(tmp)-2]*"/"; |
#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_CHECK_FILE(X) \ |
if(autoreload_on) if(Stat s=master_file_stat(X)) if(s->mtime>newest) newest=[int]s->mtime; |
|
#define AUTORELOAD_BEGIN() \ |
int ___newest=newest; \ |
newest=0 |
|
#define AUTORELOAD_FINISH(VAR, CACHE, FILE) \ |
if(autoreload_on) { \ |
mixed val = CACHE[FILE]; \ |
if(!zero_type (val) && val != no_value && newest <= load_time[FILE]) { \ |
VAR = val; \ |
} \ |
} \ |
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 // PIKE_AUTORELOAD |
|
|
|
|
|
|
|
|
|
|
program compile_string(string source, void|string filename, |
object|void handler, |
void|program p, |
void|object o) |
{ |
return compile(cpp(source, filename||"-", 1, handler, |
compat_major, compat_minor), |
handler, |
compat_major, |
compat_minor, |
p, |
o); |
} |
|
|
string master_read_file(string file) |
{ |
object o=Files()->Fd(); |
if( ([function(string, string : int)]o->open)(fakeroot(file),"r") ) |
return ([function(void : string)]o->read)(); |
return 0; |
} |
|
#ifdef GETCWD_CACHE |
static string current_path; |
int cd(string s) |
{ |
current_path=0; |
return predef::cd(s); |
} |
|
string getcwd() |
{ |
return current_path || (current_path=predef::getcwd()); |
} |
#endif // GETCWD_CACHE |
|
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 = ([]); |
|
Stat master_file_stat(string x) |
{ |
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( zero_type(d) ) |
{ |
array(string) tmp = get_dir(dir); |
if(tmp) |
{ |
#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 // FILE_STAT_CACHE |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping(string:array(string)) environment=([]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string|mapping(string:string) getenv(string|void s) |
{ |
if(!s) return [mapping(string:string)]aggregate_mapping( @(values(environment)*({}) ) ); |
#ifdef __NT__ |
s = lower_case(s); |
#endif |
return environment[s] && environment[s][1]; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
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]; |
} |
|
|
string getenv(string s) |
{ |
if(!s) return environment + ([]); |
return environment[s]; |
} |
#endif /* 0 */ |
|
|
|
|
|
|
|
|
|
void putenv(string varname, string value) |
{ |
string index = varname; |
#ifdef __NT__ |
index = lower_case(varname); |
if (environment[index] && environment[index][0]) |
varname = environment[index][0]; |
#endif |
environment[index] = ({ varname, value }); |
} |
|
|
|
|
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|NoValue) objects=([ |
this_program : this, |
object_program(_static_modules): _static_modules |
]); |
|
mapping(string:object|NoValue) fc=([]); |
|
|
|
|
|
constant no_value = (<>); |
constant NoValue = typeof (no_value); |
|
|
|
static mapping(program:string) rev_programs = ([]); |
static mapping(object:program) rev_objects = ([]); |
static 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 (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" }); |
} |
|
static class CompileCallbackError (string error_message, array error_backtrace) |
{ |
constant is_generic_error = 1; |
constant is_compile_callback_error = 1; |
} |
|
static void compile_cb_error (string msg, mixed ... args) |
|
|
|
{ |
if (sizeof (args)) msg = sprintf (msg, @args); |
array bt = backtrace(); |
bt = bt[..sizeof (bt) - 2]; |
throw (CompileCallbackError (msg, bt)); |
} |
|
static void compile_cb_rethrow (object|array err) |
|
|
|
{ |
array bt; |
if (array|object e = catch (bt = get_backtrace (err))) |
handle_error (e); |
throw (CompileCallbackError (describe_error (err), bt)); |
} |
|
static void call_compile_warning (object handler, string file, |
string msg, mixed ... args) |
{ |
if (sizeof (args)) msg = sprintf (msg, @args); |
msg = trim_all_whites (msg); |
if (handler && handler->compile_warning) |
handler->compile_warning (file, 0, msg); |
else |
compile_warning (file, 0, msg); |
} |
|
#if constant(_static_modules.Builtin.mutex) |
#define THREADED |
Builtin.mutex compilation_mutex = Builtin()->mutex(); |
#endif |
|
static program low_findprog(string pname, |
string ext, |
object|void handler, |
void|int mkobj) |
{ |
program ret; |
Stat s; |
string fname=pname+ext; |
|
resolv_debug("low_findprog(%O, %O, %O, %O)\n", |
pname, ext, handler, mkobj); |
|
#ifdef THREADED |
object key; |
|
|
|
mixed err = catch { |
key=compilation_mutex->lock(2); |
}; |
if (err) { |
werror( "low_findprog: Caught spurious error:\n" |
"%s\n", describe_backtrace(err) ); |
} |
#endif |
|
#ifdef PIKE_MODULE_RELOC |
fname = unrelocate_module(fname); |
#endif |
|
#ifdef PIKE_AUTORELOAD |
if(!autoreload_on || load_time[fname]>=time()) |
#endif |
{ |
if(!zero_type (ret=programs[fname]) && ret != no_value) { |
resolv_debug ("low_findprog %s: returning cached (no autoreload)\n", 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->isreg ) |
{ |
AUTORELOAD_BEGIN(); |
|
#ifdef PIKE_AUTORELOAD |
if (load_time[fname] > s->mtime) |
if (!zero_type (ret=programs[fname]) && ret != no_value) { |
resolv_debug ("low_findprog %s: returning cached (autoreload)\n", 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->isreg && s2->mtime >= s->mtime) |
{ |
mixed err=catch { |
AUTORELOAD_CHECK_FILE(oname); |
resolv_debug ("low_findprog %s: decoding dumped\n", fname); |
INC_RESOLV_MSG_DEPTH(); |
ret = decode_value(master_read_file(oname), |
(handler && handler->get_codec || |
get_codec)(fname, mkobj)); |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("low_findprog %s: dump decode ok\n", fname); |
return programs[fname] = ret; |
|
}; |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("low_findprog %s: dump decode failed\n", fname); |
programs[fname] = no_value; |
call_compile_warning (handler, oname, |
"Decode failed: " + 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; |
throw(e); |
} |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("low_findprog %s: compilation ok\n", fname); |
break; |
#if constant(load_module) |
case ".so": |
if (fname == "") { |
werror( "low_findprog(\"%s\", \"%s\") => load_module(\"\")\n" |
"%s\n", pname, ext, describe_backtrace(backtrace()) ); |
} |
|
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; |
compile_cb_rethrow (err); |
} |
resolv_debug ("low_findprog %s: loaded binary\n", fname); |
#endif /* load_module */ |
} |
|
AUTORELOAD_FINISH(ret,programs,fname); |
|
resolv_debug("low_findprog %s: returning %O\n", fname, ret); |
|
return programs[fname]=ret; |
} |
resolv_debug ("low_findprog %s: file not found\n", fname); |
return 0; |
} |
|
|
|
|
|
|
void unregister(program p) |
{ |
if(string fname=search(programs,p)) { |
resolv_debug("unregister %s\n", fname); |
programs[fname] = no_value; |
fname = dirname (fname); |
object n; |
if ( fname!="" && objectp (n = fc[fname]) ) |
if (n->is_resolv_dirnode || n->is_resolv_joinnode) |
n->delete_value (p); |
} |
if (objectp (objects[p])) objects[p] = no_value; |
foreach (fc; string name; mixed mod) |
if (objectp(mod) && object_program(mod) == p) |
fc[name] = no_value; |
} |
|
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; |
|
|
|
|
if(sscanf(reverse(BASENAME(pname)),"%s.%s",ext, nname)) |
{ |
ext="."+reverse(ext); |
pname=pname[..sizeof(pname)-sizeof(ext)-1]; |
} |
else { |
ext=""; |
} |
|
if(IS_ABSOLUTE_PATH(pname)) |
{ |
program|NoValue prog = programs[pname]; |
if (programp (prog)) 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) : ""); |
} |
|
|
|
|
void handle_error(array|object trace) |
{ |
if(mixed x=catch { |
werror(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%O\n", msg, bt); |
}) { |
werror("%O\n", x); |
} |
}; |
werror("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", |
"getenv", |
"putenv", |
|
#ifdef GETCWD_CACHE |
"cd", |
"getcwd", |
#endif |
}); |
|
string include_prefix; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void create() |
{ |
foreach(master_efuns, string e) |
if (this[e]) |
add_constant(e, this[e]); |
else |
error("Function %O is missing from master.pike.\n", e); |
|
add_constant("strlen", sizeof); |
add_constant("write", Files()->_stdout->write); |
|
#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 "¤include_prefix¤"[0]!='¤' |
include_prefix = "¤include_prefix¤"; |
#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])) o=objects[p]=p(); |
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) : ""); |
} |
|
|
|
static class ZERO_TYPE {}; |
|
|
|
|
|
class dirnode |
{ |
string dirname; |
object|void compilation_handler; |
constant is_resolv_dirnode = 1; |
|
|
mixed module; |
mapping(string:mixed) cache=([]); |
mapping(string:array(string)) file_paths = ([]); |
|
#ifdef __NT__ |
#define FIX_CASE(X) lower_case(X) |
#else |
#define FIX_CASE(X) (X) |
#endif /* __NT__ */ |
|
static string base_from_filename(string fname) |
{ |
string low_name = FIX_CASE(fname); |
if (has_prefix(low_name, ".#")) return 0; |
if (has_suffix(low_name, ".pike") || |
has_suffix(low_name, ".pmod")) { |
return fname[..sizeof(fname)-6]; |
} |
if (has_suffix(low_name, ".so")) { |
return fname[..sizeof(fname)-4]; |
} |
return 0; |
} |
|
static int prio_from_filename(string fname) |
{ |
fname = FIX_CASE(fname); |
if (has_suffix(fname, ".pmod")) return 3; |
if (has_suffix(fname, ".so")) return 2; |
if (has_suffix(fname, ".pike")) return 1; |
|
|
return 0; |
} |
|
static void create(string d, object|void h) |
{ |
resolv_debug ("dirnode(%O,%O) created\n",d,h); |
dirname=d; |
compilation_handler=h; |
fc[dirname]=this; |
if(has_suffix(FIX_CASE(dirname),".pmod")) { |
fc[dirname[..sizeof(dirname)-6]]=this; |
} |
array(string) files = sort(get_dir(d)||({})); |
if (!sizeof(d)) return; |
array(string) bases = map(files, base_from_filename); |
files = filter(files, bases); |
bases = filter(bases, bases); |
resolv_debug("dirnode(%O,%O) got %d files.\n", |
d, h, sizeof(bases)); |
if (!sizeof(files)) return; |
|
foreach(files; int no; string fname) { |
fname = combine_path(dirname, fname); |
string base = bases[no]; |
if (base == "module") { |
|
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..]; |
} |
} |
|
class module_checker |
{ |
int `!() |
{ |
resolv_debug ("dirnode(%O)->module_checker()->`!()\n",dirname); |
INC_RESOLV_MSG_DEPTH(); |
|
if (mixed err = catch { |
|
if (module = cache["module"] || low_ind("module", 1)) { |
|
|
|
|
cache=([]); |
_cache_full=0; |
} |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug("dirnode(%O)->module_checker()->`!() => %s\n", |
dirname, !module ? "doesn't exist" : "exists"); |
return !module; |
}) { |
|
|
|
|
|
|
|
|
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug("dirnode(%O)->module_checker()->`!() => failure, doesn't exist\n", |
dirname); |
return 1; |
} |
} |
|
mixed `[](string index) |
{ |
resolv_debug ("dirnode(%O)->module_checker()[%O] => %O\n", |
dirname, index, module && module[index]); |
return module && module[index]; |
} |
array(string) _indices() { if(module) return indices(module); } |
array _values() { if(module) return values(module); } |
} |
|
static mixed low_ind(string index, int(0..1)|void set_module) |
{ |
array(string) paths; |
|
if (!(paths = file_paths[index])) { |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug("dirnode(%O)->ind(%O) => no file match\n", |
dirname, index); |
return UNDEFINED; |
} |
|
foreach(paths, string fname) { |
resolv_debug("dirnode(%O)->ind(%O) Trying file %O...\n", |
dirname, index, fname); |
Stat stat = master_file_stat(fakeroot(fname)); |
if (!stat) { |
resolv_debug("dirnode(%O)->ind(%O) file %O disappeared!\n", |
dirname, index, fname); |
continue; |
} |
if (has_suffix(fname, ".pmod")) { |
if (stat->isdir) { |
resolv_debug("dirnode(%O)->ind(%O) => found subdirectory %O\n", |
dirname, index, fname); |
return dirnode(fname, compilation_handler); |
} |
resolv_debug("dirnode(%O)->ind(%O) casting (object)%O\n", |
dirname, index, fname); |
|
|
|
|
|
mixed ret; |
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; |
} |
} else { |
resolv_debug("dirnode(%O)->ind(%O) casting (program)%O\n", |
dirname, index, fname); |
program 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); |
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; |
} |
|
static 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(!zero_type(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); |
|
return low_ind(index); |
} |
|
mixed `[](string index) |
{ |
mixed ret; |
#ifdef MODULE_TRACE |
werror("%*nDirnode(%O) cache[%O] ?????\n", |
sizeof(backtrace()),dirname,index); |
#endif |
if(!zero_type(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] = zero_type(ret) ? ZERO_TYPE : ret; |
return ret; |
} |
|
mixed safe_index(string index) |
{ |
mixed err; |
if (err = catch { return `[](index); }) { |
call_compile_warning (compilation_handler, |
dirname+"."+fname, |
"Compilation failed: " + describe_error(err)); |
} |
return UNDEFINED; |
} |
|
static int(0..1) _cache_full; |
void fill_cache() |
{ |
#if 0 |
werror(describe_backtrace(({ sprintf("Filling cache in dirnode %O\n", |
dirname), |
backtrace() }))); |
#endif |
if (_cache_full) { |
return; |
} |
|
|
|
|
|
if (module) { |
map(indices(module), safe_index); |
} |
|
map(indices(file_paths), safe_index); |
_cache_full = 1; |
} |
|
static array(string) _indices() |
{ |
fill_cache(); |
|
|
|
|
return filter (indices (cache), map (values (cache), `!=, ZERO_TYPE)); |
} |
|
static 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; |
} |
} |
|
static int(0..) _sizeof() { |
return sizeof(_values()); |
} |
|
static string _sprintf(int as) |
{ |
return as=='O' && sprintf("master()->dirnode(%O)",dirname); |
} |
} |
|
|
|
|
|
|
class joinnode |
{ |
constant is_resolv_joinnode = 1; |
array(object|mapping) joined_modules; |
mapping(string:mixed) cache=([]); |
|
object compilation_handler; |
|
|
|
joinnode|mapping(mixed:int(0..0)) fallback_module = ([]); |
|
string _sprintf(int as) |
{ |
return as=='O' && sprintf("master()->joinnode(%O)",joined_modules); |
} |
|
static void create(array(object|mapping) _joined_modules, |
object|void _compilation_handler, |
joinnode|void _fallback_module) |
{ |
joined_modules = _joined_modules; |
compilation_handler = _compilation_handler; |
fallback_module = _fallback_module || ([]); |
resolv_debug ("joinnode(%O) created\n", joined_modules); |
} |
|
void add_path(string path) |
{ |
path = combine_path(getcwd(), path); |
dirnode node = fc[path] || |
(fc[path] = dirnode(path, compilation_handler)); |
if (sizeof(joined_modules) && |
joined_modules[0] == node) return; |
joined_modules = ({ node }) + (joined_modules - ({ node })); |
|
} |
|
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); |
}); |
|
|
} |
|
static 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 (!zero_type(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]); |
} |
|
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]; |
} |
|
mixed `[](string index) |
{ |
mixed ret; |
if (!zero_type(ret = cache[index])) { |
if (ret != ZERO_TYPE) { |
return ret; |
} |
return UNDEFINED; |
} |
ret = ind(index); |
|
|
|
if(ret == predef::__placeholder_object) return ret; |
|
if (zero_type(ret)) { |
cache[index] = ZERO_TYPE; |
} else { |
cache[index] = ret; |
} |
return ret; |
} |
|
static int _cache_full; |
|
void fill_cache() |
{ |
#if 0 |
werror(describe_backtrace(({ "Filling cache in joinnode\n", |
backtrace() }))); |
#endif |
if (_cache_full) { |
return; |
} |
foreach(joined_modules, object|mapping|program o) { |
foreach(indices(o), string index) { |
if (zero_type(cache[index])) { |
`[](index); |
} |
} |
} |
foreach(indices(fallback_module), string index) { |
`[](index); |
} |
_cache_full = 1; |
} |
|
array(string) _indices() |
{ |
fill_cache(); |
|
|
|
|
return filter (indices (cache), map (values (cache), `!=, ZERO_TYPE)); |
} |
|
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); |
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); |
} |
} |
|
int `== (mixed other) |
{ |
return objectp (other) && other->is_resolv_joinnode && |
equal (mkmultiset (joined_modules), mkmultiset (other->joined_modules)); |
} |
|
array(object) _encode() |
{ |
return joined_modules; |
} |
|
void _decode (array(object) joined_modules) |
{ |
this_program::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) |
{ |
program|object o; |
|
resolv_debug ("findmodule(%O)\n", fullname); |
if(!zero_type(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+".pmod"))) |
{ |
if(stat->isdir) |
{ |
resolv_debug ("findmodule(%O) => new dirnode\n", fullname); |
return fc[fullname] = dirnode(fullname+".pmod", handler); |
} |
} |
|
INC_RESOLV_MSG_DEPTH(); |
|
if(objectp (o = low_cast_to_object(fullname+".pmod", "/.", handler))) { |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("findmodule(%O) => got object %O\n", fullname, o); |
return fc[fullname]=o; |
} |
|
#if constant(load_module) |
if(master_file_stat(fakeroot(fullname+".so"))) { |
o = fc[fullname] = low_cast_to_object(fullname, "/.", handler); |
DEC_RESOLV_MSG_DEPTH(); |
resolv_debug ("findmodule(%O) => got .so object %O\n", fullname, o); |
return o; |
} |
#endif |
|
if (programp (o = 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", |
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(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(({predef::_static_modules})); |
|
|
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; |
|
|
|
|
|
static 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 tmp) |
{ |
tmp=normalize_path(combine_path_with_cwd(tmp)); |
root_module->add_path(tmp); |
pike_module_path = ({ tmp }) + (pike_module_path - ({ tmp })); |
} |
|
|
|
|
|
|
|
|
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, string value) |
{ |
predefines[name] = value; |
} |
|
|
|
void remove_predefine (string name) |
{ |
m_delete (predefines, name); |
} |
|
|
mapping get_predefines() |
{ |
return predefines; |
} |
|
|
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(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, |
|
@filter(root_module->joined_modules, |
lambda(mixed x) { |
return objectp(x) && x->is_resolv_dirnode; |
}) }), |
current_handler, |
root_module->fallback_module); |
|
|
|
node->cache->_static_modules = static_modules; |
|
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(zero_type(res)) error("Could not resolv %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, |
backtrace() ); |
} |
|
array(string) tmp=identifier/"."; |
mixed ret = resolv_base(tmp[0], current_file, current_handler); |
foreach(tmp[1..],string index) { |
if (zero_type(ret)) break; |
ret = ret[index]; |
} |
DEC_RESOLV_MSG_DEPTH(); |
#ifdef RESOLV_DEBUG |
if (zero_type (ret)) |
resolv_debug("resolv(%O, %O) => not found\n",identifier, current_file); |
else |
resolv_debug("resolv(%O, %O) => found %O\n",identifier, current_file, ret); |
#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); |
} |
|
string _sprintf(int t) |
{ |
return t=='O' && sprintf("CompatResolver(%O)",ver); |
} |
} |
|
inherit CompatResolver; |
|
|
class Pike06Resolver |
{ |
inherit CompatResolver; |
|
|
mixed resolv_base(string identifier, string|void current_file, |
object|void current_handler) |
{ |
if (current_file) { |
joinnode node = handle_import(".", current_file, current_handler); |
return node[identifier] || |
::resolv_base(identifier, current_file, current_handler); |
} |
return ::resolv_base(identifier, current_file, current_handler); |
} |
} |
|
|
|
string _pike_file_name; |
string _master_file_name; |
|
|
private int(0..1) _async=0; |
|
|
|
int(0..1) asyncp() { |
return _async; |
} |
|
#if constant(thread_create) |
|
static object _backend_thread=this_thread(); |
|
|
|
|
object backend_thread() |
{ |
return _backend_thread; |
} |
#endif |
|
|
mapping(string:string) initial_predefines = ([]); |
|
|
|
|
|
|
void _main(array(string) orig_argv, array(string) env) |
{ |
array(string) argv=copy_value(orig_argv); |
int debug,trace,run_tool; |
object tmp; |
string postparseaction=0; |
|
predefines = initial_predefines = |
Builtin()->_take_over_initial_predefines(); |
_pike_file_name = orig_argv[0]; |
#if constant(thread_create) |
_backend_thread = this_thread(); |
#endif |
|
foreach(env, string a) |
if( sscanf(a, "%s=%s", a, string b)==2 ) { |
#ifdef __NT__ |
if(a=="") { |
sscanf(b, "%s=%s", a, b); |
a="="+a; |
} |
#endif |
putenv(a, b); |
} |
else |
werror("Broken environment var %s\n",a); |
|
void _error(string a, mixed ... b) { |
werror(a, @b); |
exit(1); |
}; |
|
|
#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"); |
}; |
|
mixed main_resolv(string ... syms) { |
mixed v = resolv(syms[0]); |
foreach(syms[1..], string sym) |
if(v) v = v[sym]; |
if(!v) |
_error("Could not resolv %s. (Perhaps the installed pike tree has been moved.)\n", |
syms*"."); |
return v; |
}; |
|
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", NO_ARG, ({"--show-paths"}), 0, 0}), |
({"warnings", NO_ARG, ({"-w", "--warnings"}), 0, 0}), |
({"nowarnings", NO_ARG, ({"-W", "--woff", "--no-warnings"}), 0, 0}), |
({"autoreload", NO_ARG, ({"--autoreload"}), 0, 0}), |
({"master", HAS_ARG, ({"-m"}), 0, 0}), |
({"compiler_trace", NO_ARG, ({"--compiler-trace"}), 0, 0}), |
({"assembler_debug",MAY_HAVE_ARG, ({"--assembler-debug"}), 0, 0}), |
({"optimizer_debug",MAY_HAVE_ARG, ({"--optimizer-debug"}), 0, 0}), |
({"debug", MAY_HAVE_ARG, ({"--debug"}), 0, 1}), |
({"trace", MAY_HAVE_ARG, ({"--trace"}), 0, 1}), |
({"ignore", MAY_HAVE_ARG, ({"-Dqdatplr"}), 0, 1}), |
({"ignore", HAS_ARG, ({"-s"}), 0, 0}), |
({"run_tool", NO_ARG, ({"-x"}), 0, 0}), |
}), 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; |
|
#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 "nowarnings": |
want_warnings--; |
break; |
|
case "master": |
_master_file_name = q[i][1]; |
break; |
|
case "run_tool": |
run_tool = 1; |
break; |
} |
} |
|
foreach(q, array opts) |
{ |
switch(opts[0]) |
{ |
case "dumpversion": |
write("%d.%d.%d\n", __REAL_MAJOR__, __REAL_MINOR__, __REAL_BUILD__); |
exit(0); |
|
case "version": |
werror(version() + " Copyright © 1994-2004 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"); |
exit(0); |
|
case "help": |
werror( main_resolv("Tools","MasterHelp")->do_help(opts[1]) ); |
exit(0); |
|
case "features": |
postparseaction="features"; |
break; |
|
case "info": |
postparseaction="info"; |
break; |
|
case "showpaths": |
werror(format_paths()); |
exit(0); |
|
case "execute": |
#ifdef __AUTO_BIGNUM__ |
main_resolv( "Gmp", "bignum" ); |
#endif /* __AUTO_BIGNUM__ */ |
|
random_seed((time() ^ (getpid()<<8))); |
argv = tmp->get_args(argv,1); |
|
program prog; |
if(Version(compat_major,compat_minor) <= Version(7,4)) |
prog = compile_string( |
"mixed create(int argc, array(string) argv,array(string) env){"+ |
opts[1]+";}"); |
else |
prog = compile_string( |
"#define NOT(X) !(X)\n" |
"#define CHAR(X) 'X'\n" |
"mixed run(int argc, array(string) argv," |
"mapping(string:string) env){"+ |
opts[1]+";}"); |
|
#if constant(_debug) |
if(debug) _debug(debug); |
#endif |
if(trace) trace = predef::trace(trace); |
mixed ret; |
mixed err = catch { |
|
|
|
|
if(Version(compat_major,compat_minor) <= Version(7,4)) |
prog (sizeof(argv),argv,env); |
else |
ret = prog()->run(sizeof(argv),argv,getenv()); |
}; |
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": |
#ifdef __AUTO_BIGNUM__ |
main_resolv( "Gmp", "bignum" ); |
#endif /* __AUTO_BIGNUM__ */ |
write(cpp(master_read_file(opts[1]),opts[1])); |
exit(0); |
} |
} |
|
argv = tmp->get_args(argv,1); |
} |
|
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.ida.liu.se/\n" |
"\n" |
"pike binary..."+_pike_file_name+"\n"+ |
format_paths() + "\n" |
"Features......"+ |
main_resolv( "Tools","Install","features" )()*"\n "+ |
"\n"); |
exit(0); |
} |
|
#ifdef __AUTO_BIGNUM__ |
main_resolv( "Gmp", "bignum" ); |
#endif /* __AUTO_BIGNUM__ */ |
|
random_seed(time() ^ (getpid()<<8)); |
|
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" ); |
foreach (indices(ts), string s) { |
mixed val = ts[s]; |
if (programp (val)) { |
object o = val(); |
if(!o->main) continue; |
t[s] = o->description || ""; |
i = max(i, sizeof(s)); |
} |
} |
foreach(sort(indices(t)), string s) |
werror(" %-"+i+"s %s\n", s, t[s]); |
exit(1); |
} |
main_resolv( "Tools", "Hilfe" )->StdinHilfe(); |
exit(0); |
} |
else |
argv=argv[1..]; |
|
program prog; |
|
if(run_tool) { |
mixed err = catch { |
prog=main_resolv( "Tools", "Standalone", argv[0] ); |
}; |
|
if (err) |
_error( "Pike: Failed to load tool %s:\n" |
"%s\n", argv[0], |
stringp(err[0])?err[0]: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) |
_error( "Pike: Failed to compile script:\n" |
"%s\n", stringp(err[0])?err[0]:describe_backtrace(err) ); |
} |
|
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; |
if(Version(compat_major,compat_minor) <= Version(7,4)) { |
script=prog(); |
} |
else { |
script=prog(argv); |
} |
if(!script->main) |
_error("Error: %s has no main().\n", argv[0]); |
ret=script->main(sizeof(argv),argv,env); |
}; |
|
trace = predef::trace(trace); |
if (err) { |
handle_error (err); |
ret = 10; |
} |
if(!intp(ret)) { |
werror("Error: Non-integer value %O returned from main.\n", ret); |
exit(10); |
} |
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 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) */ |
|
static 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:"-",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( "%s:%s: Warning: %s\n",trim_file_name(file), |
line?(string)line:"-",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_error || |
([object]trace)->is_compilation_error)) |
|
|
return 1; |
if (objectp (trace) && ([object] trace)->is_compile_callback_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); |
} |
} |
|
|
static object _charset_mod; |
|
|
|
string decode_charset(string data, string charset) |
{ |
if (!_charset_mod) { |
object mod = [object]resolv("Locale"); |
|
_charset_mod = [object](mod && mod["Charset"]); |
if (!_charset_mod) |
compile_cb_error ("Cannot handle charset - no Locale.Charset module found."); |
} |
|
if (mixed err = catch { |
object decoder = ([function(string:object)]_charset_mod->decoder)(charset); |
return ([function(void:string)]([function(string:object)]decoder-> |
feed)(data)->drain)(); |
}) |
compile_cb_rethrow (err); |
} |
|
|
class Describer |
{ |
int clipped=0; |
int canclip=0; |
mapping(mixed:int|string) ident = ([]); |
int identcount = 0; |
|
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 (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("%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)); |
|
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": |
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; |
} |
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 program_path_to_name ( string path, |
void|string module_prefix, void|string module_suffix, |
void|string object_suffix ) |
|
|
|
|
|
|
|
|
|
|
{ |
array(string) sort_paths_by_length(array(string) paths) |
{ |
sort(map(paths, sizeof), paths); |
return reverse(paths); |
}; |
|
if (path == "/master") return "master" + (object_suffix || ""); |
|
foreach(sort_paths_by_length(map(pike_module_path - ({""}), |
lambda(string s) { |
if (s[-1] == '/') return s; |
return s+"/"; |
})), |
string prefix) { |
if (has_prefix(path, prefix)) { |
path = path[sizeof(prefix)..]; |
break; |
} |
} |
|
#if 0 |
|
|
|
path = trim_file_name(path); |
#endif |
|
string modname = replace(path, ".pmod/", "."); |
if(search(modname, "/")<0) path=modname; |
|
if (has_suffix(path, ".module.pmod")) { |
return (module_prefix || "") + path[..sizeof(path)-13] + (module_suffix || ""); |
} |
if (has_suffix(path, ".pmod")) { |
return (module_prefix || "") + path[..sizeof(path)-6] + (module_suffix || ""); |
} |
if (has_suffix(path, ".so")) { |
return (module_prefix || "") + path[..sizeof(path)-4] + (module_suffix || ""); |
} |
if (has_suffix(path, ".pike")) { |
return path[..sizeof(path)-6] + (object_suffix || ""); |
} |
return path + (object_suffix || ""); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string describe_module(object|program mod, array(object)|void ret_obj) |
{ |
|
|
|
program parent_fun = object_program(mod); |
if (parent_fun) { |
if (ret_obj) ret_obj[0] = mod; |
} else if (programp (mod)) { |
parent_fun = mod; |
|
|
if (objects && objectp (mod = objects[parent_fun]) && ret_obj) |
ret_obj[0] = mod; |
} |
else |
return ""; |
|
if (mod) { |
catch { |
string res = sprintf("%O", mod); |
if (res != "object" && res != "") |
return (objectp (objects[parent_fun]) && programs["/master"] != parent_fun? |
res+".":res+"->"); |
}; |
} |
if (!object_program(parent_fun)) { |
|
if (string path = programs_reverse_lookup (parent_fun)) |
return program_path_to_name(path, "", ".", "()->"); |
} |
|
array(object) parent_obj = ({ 0 }); |
string res = describe_module(function_object(parent_fun)|| |
function_program(parent_fun)|| |
object_program(parent_fun), |
parent_obj); |
|
object|program parent = |
object_program (parent_obj[0]) ? parent_obj[0] : object_program(parent_fun); |
if (mod && (object_program (parent) || parent)) { |
|
catch { |
|
int i = search(values(parent), mod); |
if (i >= 0) { |
return res + [string]indices(parent)[i] + "."; |
} |
}; |
} |
|
|
if (string fun_name = function_name(parent_fun)) { |
return res + fun_name + "()->"; |
} |
|
|
|
if (!mod && (object_program (parent) || parent)) { |
catch { |
|
int i; |
array(mixed) val = values(parent); |
array(string) ind = [array(string)]indices(parent); |
for (i=0; i < sizeof(val); i++) { |
if (object_program(val[i]) && object_program(val[i]) == parent_fun) { |
return res + ind[i] + "."; |
} |
} |
}; |
} |
|
|
return res + (describe_program(parent_fun)||"unknown_program") + "()->"; |
} |
|
|
string describe_object(object o) |
{ |
string s; |
if(zero_type (o)) return 0; |
|
if (o == _static_modules) return "_static_modules"; |
|
program|function(mixed...:void|object) parent_fun = object_program(o); |
|
|
catch { |
object|program parent_obj = |
(function_object(parent_fun) || function_program(parent_fun)); |
|
if (objectp (parent_obj) || parent_obj) { |
|
object tmp = objects[parent_obj]; |
if (objectp (tmp)) parent_obj = tmp; |
|
|
int i = search(values(parent_obj), o); |
if (i >= 0) { |
s = [string]indices(parent_obj)[i]; |
return describe_module(parent_obj) + s; |
} |
} |
}; |
if(objectp (objects[parent_fun])) |
if ((s = programs_reverse_lookup (parent_fun)) && |
(s=program_path_to_name(s, "", "", "()"))) |
return s; |
|
if(( s=describe_program(parent_fun) )) |
return s+"()"; |
|
return 0; |
} |
|
|
string describe_program(program|function p) |
{ |
string s; |
if(!p) return 0; |
|
if (p == object_program (_static_modules)) |
return "object_program(_static_modules)"; |
|
if(programp(p) && |
(s = programs_reverse_lookup ([program] p)) && |
(s=program_path_to_name(s, "object_program(", ")", ""))) |
return s; |
|
if(object|program tmp=(function_object(p) || function_program(p))) { |
if(s = function_name(p)) |
{ |
return describe_module(tmp) + s; |
} |
} |
|
if(s=Builtin()->program_defined(p)) |
return BASENAME(s); |
|
return 0; |
} |
|
|
string describe_function (function f) |
{ |
if (!f) return 0; |
|
string name; |
|
if(string s = programs_reverse_lookup (f)) |
{ |
if(has_suffix(s, ".pmod")) |
name = BASENAME(s[..sizeof(s)-6]); |
else |
name = trim_file_name(s); |
} |
else |
if (catch (name = function_name (f))) name = "function"; |
|
object o = function_object([function(mixed...:void|mixed)]f); |
if(object_program (o)) { |
|
|
string s; |
if (!catch (s = sprintf("%O",o)) && s != "object") |
return s+"->"+name; |
} |
return name; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string describe_backtrace(array|object 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=[int]Files()->_stdin->tcgetattr()->columns; |
}; |
if(linewidth<10) linewidth=99999; |
} |
|
|
|
if (objectp(trace) && ([object]trace)->is_generic_error) { |
object err_obj = [object] trace; |
if (mixed err = catch { |
|
if (functionp (err_obj->message)) |
ret = err_obj->message(); |
else if (zero_type (ret = err_obj->error_message)) |
|
|
ret = err_obj[0]; |
if (!ret) |
ret = ""; |
else if (!stringp (ret)) |
ret = sprintf ("<Message in %O is %t, expected string>\n", |
err_obj, ret); |
|
if (functionp (err_obj->backtrace)) |
trace = err_obj->backtrace(); |
else if (zero_type (trace = err_obj->error_backtrace)) |
|
|
trace = err_obj[1]; |
if (!trace) |
return ret + "<No backtrace>\n"; |
else if (!arrayp (trace)) |
return sprintf ("%s<Backtrace in %O is %t, expected array>\n", |
ret, err_obj, trace); |
|
}) |
return sprintf ("<Failed to index backtrace object %O: %s>\n", |
err_obj, trim_all_whites (describe_error (err))); |
} |
|
else if (arrayp(trace)) { |
if (sizeof([array]trace)==2 && stringp(ret = ([array]trace)[0])) { |
trace = ([array] trace)[1]; |
if(!trace) |
return ret + "<No backtrace>\n"; |
else if (!arrayp (trace)) |
return sprintf ("%s<Backtrace in error array is %t, expected array>\n", |
ret, trace); |
} |
} |
|
else |
return sprintf ("<Invalid backtrace/error container: %O>\n", trace); |
|
{ |
Describer desc = Describer(); |
array trace = [array]trace; |
|
int end = 0; |
if( (sizeof(trace)>1) && |
arrayp(trace[0]) && |
(sizeof([array]trace[0]) > 2) && |
(([array]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 (array err=[array]catch { |
tmp = trace[e]; |
if(stringp(tmp)) |
{ |
row=[string]tmp; |
} |
else if(arrayp(tmp)) |
{ |
if(sprintf("%t",tmp)=="object") { |
|
desc->identify_parts( tmp->args ); |
} |
else |
desc->identify_parts( tmp ); |
array tmp = [array]tmp; |
string pos; |
if(sizeof(tmp)>=2 && stringp(tmp[0])) { |
if (intp(tmp[1])) { |
pos=trim_file_name([string]tmp[0])+":"+(string)tmp[1]; |
} else { |
pos = sprintf("%s:Bad line %t", |
trim_file_name([string]tmp[0]), tmp[1]); |
} |
}else{ |
string desc="Unknown program"; |
if(sizeof(tmp)>=3 && functionp(tmp[2])) |
{ |
catch |
{ |
if(mixed tmp=function_object([function(mixed...: |
void|mixed)]tmp[2])) |
if(tmp=object_program(tmp)) |
if(tmp=describe_program([program]tmp)) |
desc=[string]tmp; |
}; |
} |
pos=desc; |
} |
|
string data; |
|
if(sizeof(tmp)>=3) |
{ |
if(functionp(tmp[2])) { |
data = describe_function ([function]tmp[2]); |
} |
else if (stringp(tmp[2])) { |
data = [string]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]); |
} |
|
int dup_frame; |
if (!zero_type(dup_frame = prev_pos[row])) { |
dup_frame -= sizeof(frames); |
if (!loop_start) { |
loop_start = dup_frame; |
loop_next = dup_frame + 1; |
loops = 0; |
continue; |
} else { |
int new_loop = 0; |
if (!loop_next) loop_next = loop_start, new_loop = 1; |
if (dup_frame == loop_next++) { |
loops += new_loop; |
continue; |
} |
} |
} |
prev_pos[row] = sizeof(frames); |
|
if (loop_start) { |
array(string) tail; |
if (!loop_next) tail = ({}), loops++; |
else tail = frames[loop_start + sizeof(frames) .. |
loop_next - 1 + sizeof(frames)]; |
if (loops) |
frames += ({sprintf ("... last %d frames above repeated %d times ...\n", |
-loop_start, loops)}); |
frames += tail; |
prev_pos = ([]); |
loop_start = 0; |
} |
|
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; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
string describe_error (object|array err) |
{ |
mixed msg; |
|
|
|
if (objectp(err) && ([object]err)->is_generic_error) { |
object err_obj = [object] err; |
if (mixed err = catch { |
|
if (functionp (err_obj->message)) |
msg = err_obj->message(); |
else if (zero_type (msg = err_obj->error_message)) |
|
|
msg = err_obj[0]; |
|
if (stringp (msg)) |
return msg; |
else if (!msg) |
return "<No error message>\n"; |
else |
return sprintf ("<Message in %O is %t, expected string>\n", |
err_obj, msg); |
|
}) |
return sprintf ("<Failed to index error object %O: %s>\n", |
err_obj, trim_all_whites (describe_error (err))); |
} |
|
else if (arrayp(err) && sizeof([array]err)==2 && |
(!(msg = ([array]err)[0]) || stringp (msg))) |
return [string] msg || "<No error message>\n"; |
|
else |
return sprintf ("<Invalid error container: %O>\n", err); |
} |
|
|
|
|
|
|
|
|
|
|
array get_backtrace (object|array err) |
{ |
array bt; |
|
|
|
if (objectp(err) && ([object]err)->is_generic_error) { |
object err_obj = [object] err; |
|
if (functionp (err_obj->backtrace)) |
bt = err_obj->backtrace(); |
else if (zero_type (bt = err_obj->error_backtrace)) |
|
|
bt = err_obj[1]; |
|
if (bt && !arrayp (bt)) |
error ("Backtrace in %O is %t, expected array.\n", err_obj, bt); |
} |
|
else if (arrayp(err) && sizeof([array]err)==2 && |
(!(bt = ([array]err)[1]) || arrayp (bt))) |
{} |
|
else if (err) |
error ("Invalid error container: %O\n", err); |
|
return bt; |
} |
|
|
#ifdef ENCODE_DEBUG |
# define ENC_MSG(X...) do werror (X); while (0) |
# define ENC_RETURN(val) do { \ |
mixed _v__ = (val); \ |
werror (" returned %s\n", \ |
zero_type (_v__) ? "UNDEFINED" : \ |
sprintf ("%O", _v__)); \ |
return _v__; \ |
} while (0) |
#else |
# define ENC_MSG(X...) do {} while (0) |
# define ENC_RETURN(val) do return (val); while (0) |
#endif |
|
#ifdef DECODE_DEBUG |
# define DEC_MSG(X...) do werror (X); while (0) |
# define DEC_RETURN(val) do { \ |
mixed _v__ = (val); \ |
werror (" returned %s\n", \ |
zero_type (_v__) ? "UNDEFINED" : \ |
sprintf ("%O", _v__)); \ |
return _v__; \ |
} while (0) |
#else |
# define DEC_MSG(X...) do {} while (0) |
# define DEC_RETURN(val) do return (val); while (0) |
#endif |
|
class Encoder |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
mixed encoded; |
|
static mapping(mixed:string) rev_constants = ([]); |
static mapping(mixed:string) rev_static_modules = ([]); |
|
static array find_index (object|program parent, mixed child, |
array(object) module_object) |
{ |
array id; |
|
find_id: { |
array inds = indices (parent), vals = values (parent); |
int i = search (vals, child); |
if (i >= 0 && parent[inds[i]] == child) { |
id = ({inds[i]}); |
ENC_MSG (" found as parent value with index %O\n", id[0]); |
} |
|
else { |
|
|
|
foreach (vals; i; mixed val) |
if (objectp (val) && child == object_program (val) && |
val == parent[inds[i]]) { |
if (module_object) { |
module_object[0] = val; |
id = ({inds[i]}); |
} |
else |
id = ({inds[i], 'p'}); |
ENC_MSG (" found as program of parent value object %O with index %O\n", |
val, id[0]); |
break find_id; |
} |
|
error ("Cannot find %O in %O.\n", child, parent); |
} |
} |
|
if (!stringp (id[0])) |
error ("Got nonstring index %O for %O in %O.\n", id[0], child, parent); |
|
return id; |
} |
|
static string|array compare_resolved (string name, mixed what, |
mixed resolved, array(object) module_object) |
{ |
array append; |
|
compare: { |
if (resolved == what) { |
ENC_MSG (" compare_resolved: %O is %O\n", what, resolved); |
break compare; |
} |
|
if (objectp (resolved)) { |
if (object_program (resolved) == what) { |
ENC_MSG (" compare_resolved: %O is program of %O\n", what, resolved); |
append = ({'p'}); |
break compare; |
} |
|
if (resolved->is_resolv_dirnode) |
if (resolved->module == what) { |
ENC_MSG (" compare_resolved: %O is dirnode module of %O\n", what, resolved); |
append = ({'m'}); |
resolved = resolved->module; |
break compare; |
} |
else if (object_program (resolved->module) == what) { |
ENC_MSG (" compare_resolved: %O is program of dirnode module of %O\n", |
what, resolved); |
append = ({'m', 'p'}); |
break compare; |
} |
else |
ENC_MSG (" compare_resolved: %O is different from dirnode module %O\n", |
what, resolved->module); |
|
#if 0 |
|
|
if (resolved->is_resolv_joinnode) { |
ENC_MSG (" compare_resolved: searching for %O in joinnode %O\n", |
what, resolved); |
foreach (resolved->joined_modules, mixed part) |
if (string|array name = compare_resolved (name, what, part, |
module_object)) { |
if (module_object) module_object[0] = resolved; |
return name; |
} |
} |
#endif |
} |
|
ENC_MSG (" compare_resolved: %O is different from %O\n", what, resolved); |
return 0; |
} |
|
name = "r" + name; |
string|array res = has_value (name, ".") ? name / "." : name; |
|
if (append) |
if (module_object) { |
|
|
|
module_object[0] = resolved; |
return res; |
} |
else |
return (arrayp (res) ? res : ({res})) + append; |
else |
return res; |
} |
|
string|array nameof (mixed what, void|array(object) module_object) |
|
|
|
|
{ |
ENC_MSG ("nameof (%t %O)\n", what, what); |
|
if (what == encoded) { |
ENC_MSG (" got the thing to encode - encoding recursively\n"); |
return UNDEFINED; |
} |
|
if (string id = rev_constants[what]) ENC_RETURN (id); |
if (string id = rev_static_modules[what]) ENC_RETURN (id); |
|
if (objectp (what)) { |
|
if (what->is_resolv_dirnode) { |
ENC_MSG (" is a dirnode\n"); |
string name = program_path_to_name (what->dirname); |
if (string|array ref = compare_resolved (name, what, resolv (name), |
module_object)) |
ENC_RETURN (ref); |
} |
|
else if (what->is_resolv_joinnode) { |
ENC_MSG (" is a joinnode\n"); |
object modules = Builtin.array_iterator (what->joined_modules); |
object|mapping value; |
check_dirnode: |
if (modules && objectp (value = modules->value()) && |
value->is_resolv_dirnode) { |
string name = program_path_to_name (value->dirname); |
modules += 1; |
foreach (modules;; value) |
if (!objectp (value) || !value->is_resolv_dirnode || |
program_path_to_name (value->dirname) != name) |
break check_dirnode; |
ENC_MSG (" joinnode has consistent name %O\n", name); |
if (string|array ref = compare_resolved (name, what, resolv (name), |
module_object)) |
ENC_RETURN (ref); |
} |
} |
|
program prog; |
if ((prog = objects_reverse_lookup (what))) |
ENC_MSG (" found program in objects: %O\n", prog); |
#if 0 |
else if ((prog = object_program (what))) |
ENC_MSG (" got program of object: %O\n", prog); |
#endif |
|
if (prog) { |
if (prog == encoded) ENC_RETURN ("o"); |
if (string path = programs_reverse_lookup (prog)) { |
ENC_MSG (" found path in programs: %O\n", path); |
string name = program_path_to_name (path); |
if (string|array ref = compare_resolved (name, |
what->_module_value || what, |
resolv (name), module_object)) |
ENC_RETURN (ref); |
else { |
ENC_MSG (" Warning: Failed to resolve; encoding path\n"); |
#ifdef PIKE_MODULE_RELOC |
ENC_RETURN ("o" + unrelocate_module (path)); |
#else |
ENC_RETURN ("o" + path); |
#endif |
} |
} |
} |
|
if (string path = fc_reverse_lookup (what)) { |
ENC_MSG (" found path in fc: %O\n", path); |
string name = program_path_to_name (path); |
if (string|array ref = compare_resolved (name, what, resolv (name), |
module_object)) |
ENC_RETURN (ref); |
else { |
ENC_MSG (" Warning: Failed to resolve; encoding path\n"); |
#ifdef PIKE_MODULE_RELOC |
ENC_RETURN ("f" + unrelocate_module (path)); |
#else |
ENC_RETURN ("f" + path); |
#endif |
} |
} |
|
if (what->_encode) { |
ENC_MSG (" object got _encode function - encoding recursively\n"); |
return UNDEFINED; |
} |
|
if (function|program prog = object_program (what)) { |
ENC_MSG (" got program of object: %O\n", prog); |
if (object|program parent = function_object (prog) || function_program (prog)) { |
ENC_MSG (" got parent of program: %O\n", parent); |
|
|
|
|
array parent_object = ({0}); |
string|array parent_name = nameof (parent, parent_object); |
if (!parent_name) { |
ENC_MSG (" inside the thing to encode - encoding recursively\n"); |
return UNDEFINED; |
} |
else { |
if (objectp (parent_object[0])) parent = parent_object[0]; |
array id = find_index (parent, what, module_object); |
if (equal (id, ({"_module_value"}))) |
ENC_RETURN (parent_name); |
else |
ENC_RETURN ((arrayp (parent_name) ? parent_name : ({parent_name})) + id); |
} |
} |
} |
|
error ("Failed to find name of unencodable object %O.\n", what); |
} |
|
if (programp (what) || functionp (what)) { |
if (string path = programs_reverse_lookup (what)) { |
ENC_MSG (" found path in programs: %O\n", path); |
string name = program_path_to_name (path); |
if (string|array ref = compare_resolved (name, what, resolv (name), |
module_object)) |
ENC_RETURN (ref); |
else { |
ENC_MSG (" Warning: Failed to resolve; encoding path\n"); |
#ifdef PIKE_MODULE_RELOC |
ENC_RETURN ("p" + unrelocate_module (path)); |
#else |
ENC_RETURN ("p" + path); |
#endif |
} |
} |
|
if (object|program parent = function_object (what) || function_program (what)) { |
ENC_MSG (" got parent: %O\n", parent); |
if (!objectp (parent)) { |
object parent_obj = objects[parent]; |
if (objectp (parent_obj)) { |
ENC_MSG (" found object for parent program in objects: %O\n", parent_obj); |
parent = parent_obj; |
} |
} |
|
array parent_object = ({0}); |
string|array parent_name = nameof (parent, parent_object); |
if (!parent_name) { |
ENC_MSG (" inside the thing to encode - encoding recursively\n"); |
return UNDEFINED; |
} |
|
else { |
if (objectp (parent_object[0])) parent = parent_object[0]; |
if (parent["_module_value"] == what && objects_reverse_lookup (parent)) { |
ENC_MSG (" found as _module_value of parent module\n"); |
ENC_RETURN (parent_name); |
} |
else { |
string|array id = function_name (what); |
if (stringp (id) && parent[id] == what) { |
ENC_MSG (" found function name in parent: %O\n", id); |
id = ({id}); |
} |
else |
id = find_index (parent, what, module_object); |
if (equal (id, ({"_module_value"}))) |
ENC_RETURN (parent_name); |
else |
ENC_RETURN ((arrayp (parent_name) ? parent_name : ({parent_name})) + id); |
} |
} |
} |
|
error ("Failed to find name of %t %O.\n", what, what); |
} |
|
|
|
|
|
ENC_MSG (" encoding recursively\n"); |
return ([])[0]; |
} |
|
mixed encode_object(object x) |
{ |
DEC_MSG ("encode_object (%O)\n", x); |
if(!x->_encode) |
error ("Cannot encode object %O without _encode function.\n", x); |
DEC_RETURN (([function]x->_encode)()); |
} |
|
static void create (void|mixed encoded) |
|
|
|
{ |
this_program::encoded = encoded; |
|
foreach (all_constants(); string var; mixed val) |
rev_constants[val] = "c" + var; |
|
rev_static_modules = |
mkmapping (values (_static_modules), |
map (indices (_static_modules), |
lambda (string name) {return "s" + name;})); |
|
#if 0 |
|
|
foreach (rev_static_modules; mixed module; string name) { |
if (objectp(module)) { |
program p = object_program(module); |
if (!rev_static_modules[p]) { |
|
rev_static_modules[p] = "s" + name; |
} |
} |
} |
#endif |
} |
} |
|
class Decoder (void|string fname, void|int mkobj) |
|
|
{ |
static int unregistered = 1; |
|
object __register_new_program(program p) |
{ |
DEC_MSG ("__register_new_program (%O)\n", p); |
if(unregistered && fname) |
{ |
unregistered = 0; |
resolv_debug("register %s\n", fname); |
programs[fname]=p; |
if (mkobj) |
DEC_RETURN (objectp (objects[p]) ? objects[p] : (objects[p]=__null_program())); |
} |
DEC_RETURN (0); |
} |
|
static mixed thingof (string|array what) |
{ |
mixed res; |
array sublist; |
if (arrayp (what)) sublist = what, what = sublist[0]; |
|
switch (what[0]) { |
case 'c': |
if (zero_type (res = all_constants()[what[1..]])) |
error ("Cannot find global constant %O.\n", what[1..]); |
break; |
case 's': |
if (zero_type (res = _static_modules[what[1..]])) |
error ("Cannot find %O in _static_modules.\n", what[1..]); |
break; |
case 'r': |
if (zero_type (res = resolv (what[1..]))) |
error ("Cannot resolve %O.\n", what[1..]); |
break; |
case 'p': |
if (!(res = low_cast_to_program (what[1..], fname, this))) |
error ("Cannot find program for %O.\n", what[1..]); |
break; |
case 'o': |
if (!objectp (res = low_cast_to_object (what[1..], fname, this))) |
error ("Cannot find object for %O.\n", what[1..]); |
break; |
case 'f': |
if (!objectp (res = findmodule (what[1..], this))) |
error ("Cannot find module for %O.\n", what[1..]); |
break; |
} |
|
DEC_MSG (" got %O\n", res); |
|
if (sublist) { |
mixed subres = res; |
for (int i = 1; i < sizeof (sublist); i++) { |
mixed op = sublist[i]; |
if (stringp (op)) { |
if (!programp (subres) && !objectp (subres) && !mappingp (subres)) |
error ("Cannot subindex %O%{[%O]%} since it's a %t.\n", |
res, sublist[1..i-1], subres); |
if (zero_type (subres = subres[op])) |
error ("Cannot find %O in %O%{[%O]%}.\n", |
op, res, sublist[1..i-1]); |
DEC_MSG (" indexed with %O: %O\n", op, subres); |
} |
else switch (op) { |
case 'm': |
if (objectp (subres) && subres->is_resolv_joinnode) { |
dirnode found; |
foreach (subres->joined_modules, object|mapping part) |
if (objectp (part) && part->is_resolv_dirnode && part->module) { |
if (found) |
error ("There are ambiguous module objects in %O.\n", |
subres); |
else |
found = part; |
} |
if (found) subres = found; |
} |
|
if (objectp (subres) && subres->is_resolv_dirnode) { |
if (subres->module) { |
subres = subres->module; |
DEC_MSG (" got dirnode module %O\n", subres); |
} |
else |
error ("Cannot find module object in dirnode %O.\n", subres); |
} |
else |
error ("Cannot get module object in thing that isn't " |
"a dirnode or unambiguous joinnode: %O\n", subres); |
break; |
|
case 'p': |
subres = object_program (subres); |
DEC_MSG (" got object_program %O\n", subres); |
break; |
|
default: |
error ("Unknown sublist operation %O in %O\n", op, what); |
} |
} |
res = subres; |
} |
|
return res; |
} |
|
object objectof (string|array what) |
{ |
DEC_MSG ("objectof (%O)\n", what); |
if (!what) { |
|
|
|
|
|
|
|
|
|
|
werror ("Warning: Decoded broken object identifier to zero.\n"); |
DEC_RETURN (0); |
} |
DEC_RETURN ([object] thingof (what)); |
} |
|
function functionof (string|array what) |
{ |
DEC_MSG ("functionof (%O)\n", what); |
DEC_RETURN ([function] thingof (what)); |
} |
|
program programof (string|array what) |
{ |
DEC_MSG ("programof (%O)\n", what); |
DEC_RETURN ([program] thingof (what)); |
} |
|
void decode_object(object o, mixed data) |
{ |
DEC_MSG ("decode_object (object(%O), %O)\n", object_program (o), data); |
if(!o->_decode) |
error ("Cannot decode object(%O) without _decode function.\n", |
object_program (o)); |
([function(mixed:void)]o->_decode)(data); |
} |
} |
|
mapping(string:Codec) codecs = set_weak_flag(([]),1); |
Codec get_codec(string|void fname, int|void mkobj) |
{ |
string key = fname + "\0" + mkobj; |
if (codecs[key]) return codecs[key]; |
return codecs[key] = Decoder(fname, mkobj); |
} |
|
class Codec |
|
|
|
{ |
inherit Encoder; |
inherit Decoder; |
|
static void create (void|mixed encoded) |
|
|
{ |
Encoder::create (encoded); |
} |
} |
|
|
inherit Codec; |
|
|
|
class Version |
{ |
|
|
int major; |
int minor; |
|
|
|
static void create(int maj, int min) |
{ |
if(maj==-1) maj = __REAL_MAJOR__; |
if(min==-1) min = __REAL_MINOR__; |
major = maj; |
minor = min; |
} |
|
#define CMP(X) ((major - ([object]X)->major) || (minor - ([object]X)->minor)) |
|
|
|
int `<(mixed v) { return objectp(v) && CMP(v) < 0; } |
int `>(mixed v) { return objectp(v) && CMP(v) > 0; } |
int `==(mixed v) { return objectp(v) && CMP(v)== 0; } |
int _hash() { return major * 4711 + minor ; } |
|
string _sprintf(int t) { |
switch(t) { |
case 's': return sprintf("%d.%d",major,minor); |
case 'O': return sprintf("%O(%s)", this_program, this); |
} |
} |
|
|
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) |
{ |
Version v=Version(major,minor); |
|
if(v > currentversion) |
{ |
|
return 0; |
} |
|
CompatResolver ret; |
|
if(!zero_type(ret=compat_handler_cache[v])) return ret; |
|
array(string) files; |
array(Version) available=({}); |
|
#if "¤share_prefix¤"[0]!='¤' |
if (!(files = get_dir("¤share_prefix¤"))) { |
werror ("Error listing directory %O: %s\n", |
"¤share_prefix¤", strerror (errno())); |
files = ({}); |
} |
foreach(files, 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]!='¤' |
if (!(files = get_dir("¤lib_prefix¤"))) { |
werror ("Error listing directory %O: %s\n", |
"¤lib_prefix¤", strerror (errno())); |
files = ({}); |
} |
foreach(files, 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 = this; |
|
foreach(reverse(available), Version tmp) |
{ |
CompatResolver compat_handler = compat_handler_cache[tmp]; |
if (!compat_handler) { |
|
|
if (tmp <= Version(0, 6)) { |
compat_handler = Pike06Resolver(tmp, ret); |
} else { |
compat_handler = CompatResolver(tmp, ret); |
} |
|
string base; |
#if "¤lib_prefix¤"[0]!='¤' |
base=combine_path("¤lib_prefix¤",sprintf("%s",tmp)); |
compat_handler->add_module_path(combine_path(base,"modules")); |
compat_handler->add_include_path(combine_path(base,"include")); |
#endif |
|
#if "¤share_prefix¤"[0]!='¤' |
base=combine_path("¤share_prefix¤",sprintf("%s",tmp)); |
compat_handler->add_module_path(combine_path(base,"modules")); |
compat_handler->add_include_path(combine_path(base,"include")); |
#endif |
|
#ifndef RESOLVER_HACK |
ret = compat_handler_cache[tmp] = compat_handler; |
#endif |
} |
} |
|
|
compat_handler_cache[v] = ret; |
|
return ret; |
} |
|
string _sprintf(int t) |
{ |
switch(t) { |
case 't': return "master"; |
case 'O': return "master()"; |
} |
} |
|
|