diff options
Diffstat (limited to 'shared/common/messtree.c')
-rw-r--r-- | shared/common/messtree.c | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/shared/common/messtree.c b/shared/common/messtree.c new file mode 100644 index 0000000..6d778aa --- /dev/null +++ b/shared/common/messtree.c @@ -0,0 +1,144 @@ +/* Copyright (c) 2005 krzYszcz and others. + * For information on usage and redistribution, and for a DISCLAIMER OF ALL + * WARRANTIES, see the file, "LICENSE.txt," in this distribution. */ + +/* This module covers parsing of a single message received by an object + or used for creation of an object, as well as parsing of multiple messages + contained in an imported buffer, etc. */ + +#include "m_pd.h" +#include "common/loud.h" +#include "messtree.h" + +#ifdef KRZYSZCZ +#define MESSTREE_DEBUG +#endif + +/* There are two different messtree structures: the compile-time input + (t_messslot/t_messnode) and the run-time one (t_messtree). The reasons are: + to allow plugins to extend a message tree, and to make the compile-time + input initializer-friendly. */ + +struct _messtree +{ + t_messslot *mt_slot; + t_symbol *mt_selector; + t_messcall mt_method; + int mt_nonexclusive; + struct _messtree *mt_sublist; + struct _messtree *mt_next; +}; + +t_messtree *messtree_new(t_symbol *selector) +{ + t_messtree *mt = getbytes(sizeof(*mt)); + mt->mt_slot = 0; + mt->mt_selector = selector; + mt->mt_method = 0; /* LATER define a default */ + mt->mt_nonexclusive = 0; + mt->mt_sublist = 0; + mt->mt_next = 0; + return (mt); +} + +static void messtree_addnode(t_messtree *mt, t_messnode *mn) +{ + /* LATER respect mn->mn_index */ + t_messslot *ms; + int i; + for (i = 0, ms = mn->mn_table + mn->mn_nslots - 1; + i < mn->mn_nslots; i++, ms--) + { + t_messtree *bch = messtree_new(gensym(ms->ms_name)); + bch->mt_slot = ms; + bch->mt_method = ms->ms_call; + bch->mt_nonexclusive = (ms->ms_flags & MESSTREE_NONEXCLUSIVE); + bch->mt_next = mt->mt_sublist; + mt->mt_sublist = bch; + if (ms->ms_subnode) + messtree_addnode(bch, ms->ms_subnode); + } +} + +void messtree_add(t_messtree *mt, t_messnode *rootnode) +{ + messtree_addnode(mt, rootnode); +} + +t_messtree *messtree_build(t_messslot *rootslot) +{ + t_messtree *mt = messtree_new(gensym(rootslot->ms_name)); + mt->mt_slot = rootslot; + mt->mt_method = rootslot->ms_call; + mt->mt_nonexclusive = (rootslot->ms_flags & MESSTREE_NONEXCLUSIVE); + mt->mt_sublist = 0; + mt->mt_next = 0; + if (rootslot->ms_subnode) + messtree_addnode(mt, rootslot->ms_subnode); + return (mt); +} + +int messtree_doit(t_messtree *mt, t_messslot **msp, int *nargp, + t_pd *target, t_symbol *s, int ac, t_atom *av) +{ + int result = MESSTREE_OK, nargpdummy; + t_messslot *mspdummy; + if (!msp) + msp = &mspdummy; + if (!nargp) + nargp = &nargpdummy; + if (s && s != mt->mt_selector) + { + loud_warning(target, (target ? 0 : "messtree"), + "unexpected selector \"%s\"", s->s_name); + *msp = 0; + *nargp = 0; + return (MESSTREE_CORRUPT); + } + if (ac && av->a_type == A_SYMBOL) + { + t_messtree *bch; + for (bch = mt->mt_sublist; bch; bch = bch->mt_next) + { + if (av->a_w.w_symbol == bch->mt_selector) + { + if (bch->mt_sublist) + return (messtree_doit(bch, msp, nargp, target, + av->a_w.w_symbol, ac - 1, av + 1)); + else + { + if (target && bch->mt_method) + result = bch->mt_method(target, av->a_w.w_symbol, + ac - 1, av + 1); + *msp = (result == MESSTREE_OK ? bch->mt_slot : 0); + *nargp = ac - 1; + return (result); + } + } + } + if (mt->mt_nonexclusive) + { + if (target && mt->mt_method) + result = mt->mt_method(target, 0, ac, av); /* LATER rethink */ + *msp = (result == MESSTREE_OK ? mt->mt_slot : 0); + *nargp = ac; + return (result); + } + else + { + loud_warning(target, (target ? 0 : "messtree"), + "unknown property \"%s\"", av->a_w.w_symbol->s_name); + *msp = 0; + *nargp = 0; + return (MESSTREE_UNKNOWN); + } + } + else + { + if (target && mt->mt_method) + result = mt->mt_method(target, 0, ac, av); + *msp = (result == MESSTREE_OK ? mt->mt_slot : 0); + *nargp = ac; + return (result); + } +} |