object $root; var $root child_index = 0; var $root child = 0; var $root inited = 1; private method .initialize(): nooverride { var ancestors, ancestor, pos, len, method; if (inited) throw(~perm, "Already initialized."); ancestors = ancestors(); len = ancestors.length(); for pos in [0 .. len - 1] { ancestor = ancestors[len - pos]; method = tosym("init_" + tostr(ancestor.objname('symbol))); catch ~methodnf { if ((.find_method(method)) != ancestor) throw(~perm, ((("Initialization method for " + (ancestor.objname())) + " in wrong place(") + (find_method(method).objname())) + ")"); .(method)(); } } inited = 1; child = 1; }; private method .uninitialize(): nooverride { var ancestor, p; for ancestor in (ancestors()) { method = tosym("uninit_" + tostr(ancestor.objname('symbol))); catch ~methodnf { if ((.find_method(method)) != ancestor) throw(~perm, ((("UnInitialization method for " + (ancestor.objname())) + " in wrong place (") + ((.find_method(method)).objname())) + ")"); .(method)(); } } for p in (.variables()) .del_var('p); }; public method .spawn(): nooverride { arg [other_parents]; var base, obj, name; if (child) throw(~perm, "Attempt to spawn a non-defining object."); name = .objname('symbol); base = tostr(name); while ((| lookup(name) |)) { child_index = child_index + 1; name = tosym((base + "_") + tostr(child_index)); } obj = (> create([this()] + other_parents) <); catch any { (> obj.initialize() <); } with { .log($parse.traceback(traceback())); if (!(| obj.destroy() |)) throw(~ack, "Unable to destroy aborted attempt", traceback()); rethrow(error()); } (> set_objname(name) <); return obj; }; public method .destroy(): nooverride { if (!child) throw(~perm, "Attempt to destroy a defining parent."); (| .uninitialize() |); destroy(this()); }; public method .set_objname(): nooverride { arg objname; if (type(objname) != 'symbol) throw(~perm, "Name is not a symbol."); // Make sure everything is lowercase. objname = tosym(lowercase(tostr(objname))); // Do nothing if objname isn't different. if (objname == (| objname() |)) return; (> set_objname(objname) <); }; public method .del_objname(): nooverride { arg name; (> del_objname(name) <); }; public method .objname(): nooverride { arg [args]; var name; name = (| objname() |); if (args) return name || 0; if (name) return "$" + tostr(name); return toliteral(this()); }; public method .parents(): nooverride { return parents(); }; public method .children(): nooverride { return children(); }; public method .descendants(): nooverride { var kids, i, c; kids = children(); while ((| (c = kids[(i = i + 1)]) |)) kids = union(kids, c.children()); return kids; }; public method .find_method() { arg method; return (> find_method(method) <); }; public method .debug(): nooverride { arg [what]; var l, line; line = ""; for l in (what) line = (line + " ") + ((type(l) == 'string) ? l | ($parse.unparse(l))); dblog("DEBUG: " + ($parse.unparse(what))); }; public method .log(): nooverride { arg what; var line; if (type(what) == 'string) { dblog(what); } else if (type(what) == 'list) { for line in (what) .log(line); } else { throw(~invarg, "Log must be called with a string or a list of strings"); } }; object $sys: $root; var $root inited = 1; var $sys startup = [$login_daemon]; driver method .startup() { arg [args]; var obj, hmm, l; dblog("" + startup); for obj in (startup) { catch any { dblog(("Calling " + (obj.objname())) + ".startup()"); (> obj.startup() <); } with { dblog("" + traceback()); catch any { for l in ($parse.traceback(traceback())) dblog(l); } with { dblog("" + traceback()); } } } set_heartbeat(5); }; driver method .signal() { arg [args]; };