mirror of
git://git.psyced.org/git/psyced
synced 2024-08-15 03:25:10 +00:00
129 lines
5.3 KiB
C
129 lines
5.3 KiB
C
// $Id: signature.c,v 1.17 2008/03/11 13:42:26 lynx Exp $ // vim:syntax=lpc
|
|
//
|
|
// generic implementation of http://about.psyc.eu/Signature
|
|
//
|
|
// maps an anonymous ordered value list to a named parametric var mapping
|
|
// according to the signature of a method. probably should
|
|
// also be able to do it in the other direction.
|
|
//
|
|
// needed both for converting slash commands into _request commands
|
|
// and to implement a protocol level optimization where variable names
|
|
// can be left out as long as the values are in the proper order.
|
|
//
|
|
// currently we only do the first of the two applications (actually the
|
|
// second being an extension of the first). to achieve that we hold a hash
|
|
// of command methods which point to their respective signatures.
|
|
|
|
#include <net.h>
|
|
#include <signature.h>
|
|
|
|
/* we still don't use structs because they make the driver a lot fatter
|
|
* we'll get by using arrays and a couple of macros from signature.h
|
|
*
|
|
struct Signature {
|
|
closure handler;
|
|
mixed extra;
|
|
array(string) vars;
|
|
};
|
|
*
|
|
* also, we don't use closures as closures stick to the blueprint instead
|
|
* of operating on the working object. apparently bind_lambda() can rebind
|
|
* a CLOSURE_LFUN, but i didn't find out how to create that type of closure
|
|
* and having something like
|
|
* if (blueprintp(ME)) return
|
|
* previous_object()->myself(myargs);
|
|
* in *each* handler is a very ugly enterprise. I finally decided that the
|
|
* little performance trade off in looking up an object's function in its
|
|
* function table is well worth the simplicity we get by keeping all
|
|
* signatures in a central place, being here. first I tried to make a custom
|
|
* signature hash for each blueprint of a place, but that is just too messy
|
|
* to go for.
|
|
*/
|
|
|
|
// these could be generated by an external tool
|
|
private volatile mapping _sigs = ([
|
|
// "OFFICIAL" METHODS as seen on [[Command]].
|
|
// ahem... _do? consistency please!
|
|
"_request_do_show_log": ({ "_request_history", 0, "_parameter" }),
|
|
// can either be _amount or _match or _parameter
|
|
"_request_history": ({ "_request_history", 0, "_parameter" }),
|
|
"_request_kick": ({ "_request_kick", 0, "_person" }),
|
|
"_request_nickname": ({ "_request_nick_local", 0, "_nick_local", "_INTERNAL_stuss" }),
|
|
// the real thing, maybe? method inheritance could even lead to here
|
|
// for all of the _request_set_something methods. good? bad?
|
|
"_request_set": ({ "_request_set", 0, "_key", "_value" }),
|
|
// when called by _request_set(), value might be in _value
|
|
"_request_set_masquerade": ({ "_request_masquerade", 0, "_flag_masquerade" }),
|
|
"_request_set_owners": ({ "_request_owners", 0, "_list_owners" }), // _tab
|
|
"_request_set_public": ({ "_request_public", 0, "_flag_public" }),
|
|
"_request_set_style": ({ "_request_set_style", 0, "_uniform_style" }),
|
|
// "INTERNAL" METHODS
|
|
// all of the following "fake" _request methods are just the psyced
|
|
// way to handle command name variations and shortcuts. never use this
|
|
// in your clients. always use the official versions listed on
|
|
// [[Command]]. when sending arbitrary commands, use _request_execute,
|
|
// don't make up _request_something like psyced does internally.
|
|
"_request_hist": ({ "_request_history", 0, "_parameter" }),
|
|
"_request_style": ({ "_request_set_style", 0, "_uniform_style" }),
|
|
"_request_owners": ({ "_request_owners", 0, "_list_owners" }), // _tab
|
|
"_request_elrid": ({ "_request_kick", 0, "_person" }),
|
|
"_request_masquerade": ({ "_request_masquerade", 0, "_flag_masquerade" }),
|
|
"_request_masq": ({ "_request_masquerade", 0, "_flag_masquerade" }),
|
|
"_request_nick": ({ "_request_nick_local", 0, "_nick_local", "_INTERNAL_stuss" }),
|
|
"_request_ni": ({ "_request_nick_local", 0, "_nick_local", "_INTERNAL_stuss" }),
|
|
"_request_public": ({ "_request_public", 0, "_flag_public" }),
|
|
"_request_pub": ({ "_request_public", 0, "_flag_public" }),
|
|
#ifdef EXPERIMENTAL
|
|
// stuff to play around with
|
|
"_request_pset": ({ "_request_set", 0, "_key", "_value" }),
|
|
"_request_cset": ({ "_request_set", 0, "_key_set", "_value" }),
|
|
"_request_tt": ({ "_request_set", ([ "_key": "_topic" ]), "_value" }),
|
|
#endif
|
|
]);
|
|
|
|
varargs int call_signature(string source, string mc, mixed data,
|
|
mapping origvars, varargs array(mixed) more) {
|
|
Signature s = _sigs[mc];
|
|
mapping vars;
|
|
string last;
|
|
int i, j;
|
|
|
|
unless (s) return 0;
|
|
// ASSERT("call_signature:closurep", closurep(s[SHandler]), s)
|
|
// vars = ([ "_INTERNAL_method_signature": mc ]);
|
|
vars = ([]);
|
|
if (mappingp(origvars) && sizeof(origvars))
|
|
vars += origvars;
|
|
if (mappingp(s[SPreset])) vars += s[SPreset];
|
|
/* else if (s[SPreset])
|
|
vars["_INTERNAL_preset"] = s[SPreset]; */
|
|
if (pointerp(data) && sizeof(data)) {
|
|
vars["_INTERNAL_command"] = data[0];
|
|
for (i=1, j=SKeys; i<sizeof(data); i++, j++) {
|
|
if (j < sizeof(s))
|
|
// check var type here.. TODO
|
|
vars[ last = s[j] ] = data[i];
|
|
else
|
|
vars[ last ] += " "+ data[i];
|
|
}
|
|
data = 0;
|
|
}
|
|
P2(("call_signature: created %O as vars\n", vars))
|
|
// this is how i tried to do it with closures..
|
|
//bind_lambda(s[SHandler]);
|
|
//return apply(s[SHandler], vars, more);
|
|
return call_direct(previous_object(), s[SHandler],
|
|
source, mc, data, vars, more...);
|
|
}
|
|
|
|
#ifdef _flag_extend_backend
|
|
mapping register_signature(mapping newsigs) {
|
|
if (newsigs) {
|
|
_sigs = newsigs;
|
|
ASSERT("register_signature",
|
|
mappingp(_sigs) && sizeof(_sigs), _sigs)
|
|
}
|
|
return _sigs;
|
|
}
|
|
#endif
|
|
|