diff options
Diffstat (limited to 'shared/common')
-rw-r--r-- | shared/common/Makefile.sources | 1 | ||||
-rw-r--r-- | shared/common/fitter.c | 237 | ||||
-rw-r--r-- | shared/common/fitter.h | 6 | ||||
-rw-r--r-- | shared/common/loud.c | 16 | ||||
-rw-r--r-- | shared/common/loud.h | 2 | ||||
-rw-r--r-- | shared/common/messtree.c | 144 | ||||
-rw-r--r-- | shared/common/messtree.h | 47 | ||||
-rw-r--r-- | shared/common/os.c | 99 | ||||
-rw-r--r-- | shared/common/os.h | 15 | ||||
-rw-r--r-- | shared/common/port.c | 6 | ||||
-rw-r--r-- | shared/common/qtree.c | 208 | ||||
-rw-r--r-- | shared/common/qtree.h | 11 |
12 files changed, 674 insertions, 118 deletions
diff --git a/shared/common/Makefile.sources b/shared/common/Makefile.sources index 33bf597..72977d2 100644 --- a/shared/common/Makefile.sources +++ b/shared/common/Makefile.sources @@ -6,6 +6,7 @@ fitter.c \ grow.c \ lex.c \ loud.c \ +messtree.c \ mifi.c \ os.c \ patchvalue.c \ diff --git a/shared/common/fitter.c b/shared/common/fitter.c index faba970..48e5653 100644 --- a/shared/common/fitter.c +++ b/shared/common/fitter.c @@ -17,107 +17,156 @@ /* FIXME compatibility mode should be a standard Pd feature. When it is, it will be possible to simplify the implementation. Until then, - we have to handle multiple copies of the 'fittermode_value' variable + we have to handle multiple copies of the 'fitterstate_mode' variable (coming from different externals), and the only way is multicasting - through a symbol (#compatibility). */ -static t_symbol *fittermode_value = 0; - -typedef struct _fittermode_client -{ - t_class *fc_owner; - t_canvas *fc_canvas; - t_fittermode_callback fc_callback; - struct _fittermode_client *fc_next; -} t_fittermode_client; - -static t_fittermode_client *fittermode_clients = 0; -static t_class *fittermode_class = 0; -static t_pd *fittermode_target = 0; -static int fittermode_ready = 0; -static t_symbol *fitterps_hashcompatibility = 0; + through a symbol (#miXed). */ +static t_symbol *fitterstate_mode = 0; + +/* FIXME keep state in an extensible fitterstate_dictionary */ +static t_symbol *fitterstate_test = 0; + +typedef struct _fitterstate_client +{ + t_class *fc_owner; + t_canvas *fc_canvas; + t_fitterstate_callback fc_callback; + struct _fitterstate_client *fc_next; +} t_fitterstate_client; + +static t_fitterstate_client *fitterstate_clients = 0; +static t_class *fitterstate_class = 0; +static t_pd *fitterstate_target = 0; +static int fitterstate_ready = 0; +static t_symbol *fitterps_hashmiXed = 0; +static t_symbol *fitterps_mode = 0; +static t_symbol *fitterps_test = 0; static t_symbol *fitterps_max = 0; static t_symbol *fitterps_none = 0; -/* read access (query), only from fittermode_dosetup() */ -static void fittermode_bang(t_pd *x) +/* read access (query), called only from fitterstate_dosetup() + or through "#miXed" */ +static void fitterstate_bang(t_pd *x) { - if (fitterps_hashcompatibility) + if (fitterps_hashmiXed) { - if (fittermode_ready /* do not reply to own request */ - && fitterps_hashcompatibility->s_thing) - /* this proliferates for the third and subsequent - fittermode_dosetup() calls... */ - pd_symbol(fitterps_hashcompatibility->s_thing, - fittermode_value); + if (fitterstate_ready /* do not reply to own request */ + && fitterps_hashmiXed->s_thing) + { + t_atom atout[2]; + /* these proliferate for the third and subsequent + fitterstate_dosetup() calls... */ + SETSYMBOL(&atout[0], fitterps_mode); + SETSYMBOL(&atout[1], fitterstate_mode); + typedmess(fitterps_hashmiXed->s_thing, gensym("reply"), 2, atout); + SETSYMBOL(&atout[0], fitterps_test); + SETSYMBOL(&atout[1], fitterstate_test); + typedmess(fitterps_hashmiXed->s_thing, gensym("reply"), 2, atout); + } } - else loudbug_bug("fittermode_bang"); + else loudbug_bug("fitterstate_bang"); } -/* read access (reply), only from fitter_dosetup() */ -static void fittermode_symbol(t_pd *x, t_symbol *s) +/* read access (query), called only through "#miXed" */ +static void fitterstate_symbol(t_pd *x, t_symbol *s) { - if (!s || s == &s_) + if (fitterstate_ready && fitterps_hashmiXed && fitterps_hashmiXed->s_thing) { - loudbug_bug("fittermode_symbol"); - s = fitterps_none; + t_atom atout[2]; + if (s == fitterps_mode) + { + SETSYMBOL(&atout[0], fitterps_mode); + SETSYMBOL(&atout[1], fitterstate_mode); + typedmess(fitterps_hashmiXed->s_thing, gensym("reply"), 2, atout); + } + else if (s == fitterps_test) + { + SETSYMBOL(&atout[0], fitterps_test); + SETSYMBOL(&atout[1], fitterstate_test); + typedmess(fitterps_hashmiXed->s_thing, gensym("reply"), 2, atout); + } + else post("\"%s\": no such key in the miXed state", + (s ? s->s_name : "???")); } - fittermode_value = s; + else loudbug_bug("fitterstate_symbol"); } -/* write access, only from fitter_setmode() */ -static void fittermode_set(t_pd *x, t_symbol *s) +/* read access (reply), called only from fitter_dosetup() or through "#miXed" */ +static void fitterstate_reply(t_pd *x, t_symbol *s1, t_symbol *s2) { - t_fittermode_client *fc; - fittermode_value = s; - for (fc = fittermode_clients; fc; fc = fc->fc_next) + if (!s2 || s2 == &s_) + { + loudbug_bug("fitterstate_reply"); + s2 = fitterps_none; + } + if (s1 == fitterps_mode) + fitterstate_mode = s2; + else if (s1 == fitterps_test) + fitterstate_test = s2; +} + +/* write access, called only from fitter_setmode() or through "#miXed" */ +static void fitterstate_set(t_pd *x, t_symbol *s1, t_symbol *s2) +{ + t_fitterstate_client *fc; + if (s1 == fitterps_mode) + fitterstate_mode = s2; + else if (s1 == fitterps_test) + fitterstate_test = s2; + for (fc = fitterstate_clients; fc; fc = fc->fc_next) if (fc->fc_callback) fc->fc_callback(); } -static void fittermode_dosetup(int noquery) +static void fitterstate_dosetup(int noquery) { - if (fittermode_class || fittermode_target) - loudbug_bug("fittermode_dosetup"); - fitterps_hashcompatibility = gensym("#compatibility"); + if (fitterstate_class || fitterstate_target) + loudbug_bug("fitterstate_dosetup"); + fitterps_hashmiXed = gensym("#miXed"); + fitterps_mode = gensym("mode"); + fitterps_test = gensym("test"); fitterps_max = gensym("max"); fitterps_none = gensym("none"); - fittermode_value = fitterps_none; - fittermode_class = class_new(fitterps_hashcompatibility, - 0, 0, sizeof(t_pd), - CLASS_PD | CLASS_NOINLET, 0); - class_addbang(fittermode_class, fittermode_bang); - class_addsymbol(fittermode_class, fittermode_symbol); - class_addmethod(fittermode_class, - (t_method)fittermode_set, - gensym("set"), A_SYMBOL, 0); - fittermode_target = pd_new(fittermode_class); - pd_bind(fittermode_target, fitterps_hashcompatibility); + fitterstate_mode = fitterps_none; + fitterstate_test = fitterps_none; + fitterstate_class = class_new(fitterps_hashmiXed, + 0, 0, sizeof(t_pd), + CLASS_PD | CLASS_NOINLET, 0); + class_addbang(fitterstate_class, fitterstate_bang); + class_addsymbol(fitterstate_class, fitterstate_symbol); + class_addmethod(fitterstate_class, + (t_method)fitterstate_reply, + gensym("reply"), A_SYMBOL, A_SYMBOL, 0); + class_addmethod(fitterstate_class, + (t_method)fitterstate_set, + gensym("set"), A_SYMBOL, A_SYMBOL, 0); + fitterstate_target = pd_new(fitterstate_class); + pd_bind(fitterstate_target, fitterps_hashmiXed); if (!noquery) - pd_bang(fitterps_hashcompatibility->s_thing); - fittermode_ready = 1; + pd_bang(fitterps_hashmiXed->s_thing); + fitterstate_ready = 1; } -void fitter_setup(t_class *owner, t_fittermode_callback callback) +void fitter_setup(t_class *owner, t_fitterstate_callback callback) { - if (!fittermode_class) - fittermode_dosetup(0); + if (!fitterstate_class) + fitterstate_dosetup(0); if (callback) { - t_fittermode_client *fc = getbytes(sizeof(*fc)); + t_fitterstate_client *fc = getbytes(sizeof(*fc)); fc->fc_owner = owner; fc->fc_canvas = 0; /* a global client */ fc->fc_callback = callback; - fc->fc_next = fittermode_clients; - fittermode_clients = fc; + fc->fc_next = fitterstate_clients; + fitterstate_clients = fc; } } void fitter_drop(t_class *owner) { - if (fittermode_class && fitterps_hashcompatibility->s_thing) + if (fitterstate_class && fitterps_hashmiXed->s_thing) { - t_fittermode_client *fcp = 0, - *fc = fittermode_clients; + t_fitterstate_client *fcp = 0, + *fc = fitterstate_clients; while (fc) { if (fc->fc_owner == owner) @@ -125,7 +174,7 @@ void fitter_drop(t_class *owner) if (fcp) fcp->fc_next = fc->fc_next; else - fittermode_clients = fc->fc_next; + fitterstate_clients = fc->fc_next; break; } fcp = fc; @@ -139,48 +188,72 @@ void fitter_drop(t_class *owner) else loudbug_bug("fitter_drop 2"); } +t_float *fitter_getfloat(t_symbol *s) +{ + if (!fitterstate_class) + fitterstate_dosetup(0); + loudbug_bug("fitter_getfloat"); + return (0); +} + +t_symbol *fitter_getsymbol(t_symbol *s) +{ + if (!fitterstate_class) + fitterstate_dosetup(0); + if (s == fitterps_mode) + return (fitterstate_mode); + else if (s == fitterps_test) + return (fitterstate_test); + else + { + loudbug_bug("fitter_getsymbol"); + return (0); + } +} + void fitter_setmode(t_symbol *s) { if (!s || s == &s_) s = fitterps_none; post("setting compatibility mode to '%s'", s->s_name); - if (!fittermode_class) - fittermode_dosetup(1); - if (fitterps_hashcompatibility->s_thing) + if (!fitterstate_class) + fitterstate_dosetup(1); + if (fitterps_hashmiXed->s_thing) { - t_atom at; - SETSYMBOL(&at, s); - typedmess(fitterps_hashcompatibility->s_thing, gensym("set"), 1, &at); + t_atom atout[2]; + SETSYMBOL(&atout[0], fitterps_mode); + SETSYMBOL(&atout[1], s); + typedmess(fitterps_hashmiXed->s_thing, gensym("set"), 2, atout); } else loudbug_bug("fitter_setmode"); } t_symbol *fitter_getmode(void) { - if (!fittermode_class) - fittermode_dosetup(0); - return (fittermode_value); + if (!fitterstate_class) + fitterstate_dosetup(0); + return (fitterstate_mode); } void fittermax_set(void) { - if (!fittermode_class) - fittermode_dosetup(0); + if (!fitterstate_class) + fitterstate_dosetup(0); fitter_setmode(fitterps_max); } int fittermax_get(void) { - if (!fittermode_class) - fittermode_dosetup(0); - return (fittermode_value == fitterps_max); + if (!fitterstate_class) + fitterstate_dosetup(0); + return (fitterstate_mode == fitterps_max); } void fittermax_warning(t_class *c, char *fmt, ...) { - if (!fittermode_class) - fittermode_dosetup(0); - if (fittermode_value == fitterps_max) + if (!fitterstate_class) + fitterstate_dosetup(0); + if (fitterstate_mode == fitterps_max) { char buf[MAXPDSTRING]; va_list ap; diff --git a/shared/common/fitter.h b/shared/common/fitter.h index 2e5c24d..a6797e5 100644 --- a/shared/common/fitter.h +++ b/shared/common/fitter.h @@ -5,10 +5,12 @@ #ifndef __FITTER_H__ #define __FITTER_H__ -typedef void (*t_fittermode_callback)(void); +typedef void (*t_fitterstate_callback)(void); -void fitter_setup(t_class *owner, t_fittermode_callback callback); +void fitter_setup(t_class *owner, t_fitterstate_callback callback); void fitter_drop(t_class *owner); +t_float *fitter_getfloat(t_symbol *s); +t_symbol *fitter_getsymbol(t_symbol *s); void fitter_setmode(t_symbol *s); t_symbol *fitter_getmode(void); void fittermax_set(void); diff --git a/shared/common/loud.c b/shared/common/loud.c index e1e921d..7129962 100644 --- a/shared/common/loud.c +++ b/shared/common/loud.c @@ -88,12 +88,18 @@ void loud_errand(t_pd *x, char *fmt, ...) va_end(ap); } -void loud_syserror(t_pd *x, char *msg) +void loud_syserror(t_pd *x, char *fmt, ...) { - if (msg) - loud_error(x, "%s (%s)", msg, strerror(errno)); - else - loud_error(x, strerror(errno)); + if (fmt) + { + char buf[MAXPDSTRING]; + va_list ap; + va_start(ap, fmt); + vsprintf(buf, fmt, ap); + loud_error(x, "%s (%s)", buf, strerror(errno)); + va_end(ap); + } + else loud_error(x, strerror(errno)); } void loud_nomethod(t_pd *x, t_symbol *s) diff --git a/shared/common/loud.h b/shared/common/loud.h index 297b9c1..9497e0d 100644 --- a/shared/common/loud.h +++ b/shared/common/loud.h @@ -18,7 +18,7 @@ int shared_matchignorecase(char *test, char *pattern); char *loud_ordinal(int n); void loud_error(t_pd *x, char *fmt, ...); void loud_errand(t_pd *x, char *fmt, ...); -void loud_syserror(t_pd *x, char *msg); +void loud_syserror(t_pd *x, char *fmt, ...); void loud_nomethod(t_pd *x, t_symbol *s); void loud_messarg(t_pd *x, t_symbol *s); int loud_checkint(t_pd *x, t_float f, int *valuep, t_symbol *mess); 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); + } +} diff --git a/shared/common/messtree.h b/shared/common/messtree.h new file mode 100644 index 0000000..a3a3326 --- /dev/null +++ b/shared/common/messtree.h @@ -0,0 +1,47 @@ +/* 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. */ + +#ifndef __MESSTREE_H__ +#define __MESSTREE_H__ + +typedef int (*t_messcall)(t_pd *, t_symbol *, int, t_atom *); +typedef char *t_messarg; + +typedef struct _messslot +{ + char *ms_name; + t_messcall ms_call; + char *ms_argument; + int ms_flags; + struct _messnode *ms_subnode; +} t_messslot; + +typedef struct _messnode /* a parser's symbol definition, sort of... */ +{ + t_messslot *mn_table; + int mn_nslots; + int mn_index; +} t_messnode; + +EXTERN_STRUCT _messtree; +#define t_messtree struct _messtree + +#define MESSTREE_NSLOTS(slots) (sizeof(slots)/sizeof(*(slots))) + +enum { MESSTREE_OK, /* done current message parsing, parse next */ + MESSTREE_CONTINUE, /* continue current message parsing */ + MESSTREE_UNKNOWN, /* current message unknown, parse next */ + MESSTREE_CORRUPT, /* current message corrupt, parse next */ + MESSTREE_FATAL /* exit parsing */ +}; + +#define MESSTREE_NONEXCLUSIVE 1 + +t_messtree *messtree_new(t_symbol *selector); +void messtree_add(t_messtree *mt, t_messnode *rootnode); +t_messtree *messtree_build(t_messslot *rootslot); +int messtree_doit(t_messtree *mt, t_messslot **msp, int *nargp, + t_pd *target, t_symbol *s, int ac, t_atom *av); + +#endif diff --git a/shared/common/os.c b/shared/common/os.c index 9129f82..408fdfb 100644 --- a/shared/common/os.c +++ b/shared/common/os.c @@ -6,6 +6,7 @@ #include <io.h> #else #include <unistd.h> +#include <dirent.h> #endif #include <stdlib.h> #include <stdio.h> @@ -233,3 +234,101 @@ FILE *filewrite_open(char *filename, t_canvas *cv, int textmode) sys_bashfilename(path, path); return (fopen(path, (textmode ? "w" : "wb"))); } + +/* FIXME add MSW */ + +struct _osdir +{ +#ifndef MSW + DIR *dir_handle; + struct dirent *dir_entry; +#endif + int dir_flags; +}; + +/* returns 0 on error, a caller is then expected to call + loud_syserror(owner, "cannot open \"%s\"", dirname) */ +t_osdir *osdir_open(char *dirname) +{ +#ifndef MSW + DIR *handle = opendir(dirname); + if (handle) + { +#endif + t_osdir *dp = getbytes(sizeof(*dp)); +#ifndef MSW + dp->dir_handle = handle; + dp->dir_entry = 0; +#endif + dp->dir_flags = 0; + return (dp); +#ifndef MSW + } + else return (0); +#endif +} + +void osdir_setmode(t_osdir *dp, int flags) +{ + if (dp) + dp->dir_flags = flags; +} + +void osdir_close(t_osdir *dp) +{ + if (dp) + { +#ifndef MSW + closedir(dp->dir_handle); +#endif + freebytes(dp, sizeof(*dp)); + } +} + +void osdir_rewind(t_osdir *dp) +{ + if (dp) + { +#ifndef MSW + rewinddir(dp->dir_handle); + dp->dir_entry = 0; +#endif + } +} + +char *osdir_next(t_osdir *dp) +{ +#ifndef MSW + if (dp) + { + while (dp->dir_entry = readdir(dp->dir_handle)) + { + if (!dp->dir_flags || + (dp->dir_entry->d_type == DT_REG + && (dp->dir_flags & OSDIR_FILEMODE)) || + (dp->dir_entry->d_type == DT_DIR + && (dp->dir_flags & OSDIR_DIRMODE))) + return (dp->dir_entry->d_name); + } + } +#endif + return (0); +} + +int osdir_isfile(t_osdir *dp) +{ +#ifndef MSW + return (dp && dp->dir_entry && dp->dir_entry->d_type == DT_REG); +#else + return (0); +#endif +} + +int osdir_isdir(t_osdir *dp) +{ +#ifndef MSW + return (dp && dp->dir_entry && dp->dir_entry->d_type == DT_DIR); +#else + return (0); +#endif +} diff --git a/shared/common/os.h b/shared/common/os.h index f3dde89..7bf3c9a 100644 --- a/shared/common/os.h +++ b/shared/common/os.h @@ -5,9 +5,24 @@ #ifndef __OS_H__ #define __OS_H__ +EXTERN_STRUCT _osdir; +#define t_osdir struct _osdir + +#define OSDIR_FILEMODE 1 +#define OSDIR_DIRMODE 2 + int ospath_length(char *path, char *cwd); char *ospath_absolute(char *path, char *cwd, char *result); + FILE *fileread_open(char *filename, t_canvas *cv, int textmode); FILE *filewrite_open(char *filename, t_canvas *cv, int textmode); +t_osdir *osdir_open(char *dirname); +void osdir_setmode(t_osdir *dp, int flags); +void osdir_close(t_osdir *dp); +void osdir_rewind(t_osdir *dp); +char *osdir_next(t_osdir *dp); +int osdir_isfile(t_osdir *dp); +int osdir_isdir(t_osdir *dp); + #endif diff --git a/shared/common/port.c b/shared/common/port.c index 5845210..fe58b6e 100644 --- a/shared/common/port.c +++ b/shared/common/port.c @@ -35,8 +35,10 @@ #define PORT_INISTACK 256 /* LATER rethink */ #define PORT_INISIZE 512 /* LATER rethink */ -enum { PORT_OK, - PORT_NEXT, /* next line, please */ +/* FIXME use messtree api */ + +enum { PORT_OK, /* MESSTREE_CONTINUE */ + PORT_NEXT, /* next line, please: MESSTREE_OK */ PORT_UNKNOWN, PORT_CORRUPT, PORT_FATAL }; /* cf binport.c */ diff --git a/shared/common/qtree.c b/shared/common/qtree.c index 3d35769..b749b3a 100644 --- a/shared/common/qtree.c +++ b/shared/common/qtree.c @@ -294,7 +294,7 @@ static t_qnode *qtree_postinserthook(t_qnode *np) (which means foundp returns 1), a new node is inserted, unless hook is either empty, or returns null. Hook's nonempty return is the parent for the new node. It is expected to have no more than one child. */ -static t_qnode *qtree_doinsert(t_qtree *tree, double key, +static t_qnode *qtree_doinsert(t_qtree *tree, double key, t_qnode *preexisting, t_qtree_inserthook hook, int *foundp) { t_qnode *np, *parent, *result; @@ -302,11 +302,18 @@ static t_qnode *qtree_doinsert(t_qtree *tree, double key, *foundp = 0; if (!(np = tree->t_root)) { - if (!(np = getbytes(tree->t_nodesize))) + if (!(np = (tree->t_nodesize > 0 ? + getbytes(tree->t_nodesize) : preexisting))) + { + if (tree->t_nodesize == 0) + loudbug_bug("qtree_insert, node not supplied"); return (0); + } np->n_key = key; np->n_black = 1; + np->n_left = np->n_right = np->n_parent = 0; tree->t_root = tree->t_first = tree->t_last = np; + np->n_prev = np->n_next = 0; return (np); } @@ -343,8 +350,13 @@ static t_qnode *qtree_doinsert(t_qtree *tree, double key, addit: /* parent has no more than one child, new node becomes parent's immediate successor or predecessor */ - if (!(np = getbytes(tree->t_nodesize))) + if (!(np = (tree->t_nodesize > 0 ? + getbytes(tree->t_nodesize) : preexisting))) + { + if (tree->t_nodesize == 0) + loudbug_bug("qtree_insert, node not supplied"); return (0); + } np->n_key = key; np->n_parent = parent; if (leftchild) @@ -440,7 +452,8 @@ void qtree_delete(t_qtree *tree, t_qnode *gone) of gone's parent (if any). Successor always exists in this context, and it has no left child. The simplistic scheme is to replace gone's fields with successor's fields, and delete the successor. - We cannot do so, however, because successor may be pointed at... */ + We cannot do so, however, because 1. nodes may be caller-owned + (nodesize == 0), 2. successor may be pointed at... */ t_qnode *successor = gone->n_next; child = successor->n_right; successor->n_left = gone->n_left; @@ -624,7 +637,8 @@ void qtree_delete(t_qtree *tree, t_qnode *gone) child->n_black = 1; } done: - freebytes(gone, tree->t_nodesize); + if (tree->t_nodesize) + freebytes(gone, tree->t_nodesize); #ifdef QTREE_DEBUG qtree_verify(tree); #endif @@ -638,41 +652,189 @@ t_qnode *qtree_search(t_qtree *tree, double key) return (np); } -t_qnode *qtree_closest(t_qtree *tree, double key, int geqflag) +/* Returns the greatest node <= key, if any (may return null). + If deltap is not null, it will hold the abs diff (key - node.n_key). */ +t_qnode *qtree_closestunder(t_qtree *tree, double key, double *deltap) { t_qnode *np, *parent; if (!(np = tree->t_root)) return (0); do if (np->n_key == key) + { + if (deltap) + *deltap = 0.; return (np); - else - parent = np; + } + else parent = np; + while (np = (key < np->n_key ? np->n_left : np->n_right)); + if (np = (key < parent->n_key ? parent->n_prev : parent)) + { + if (deltap) + *deltap = key - np->n_key; + return (np); + } + else return (0); +} + +/* Returns the smallest node >= key, if any (may return null). + If deltap is not null, it will hold the abs diff (node.n_key - key). */ +t_qnode *qtree_closestover(t_qtree *tree, double key, double *deltap) +{ + t_qnode *np, *parent; + if (!(np = tree->t_root)) + return (0); + do + if (np->n_key == key) + { + if (deltap) + *deltap = 0.; + return (np); + } + else parent = np; while (np = (key < np->n_key ? np->n_left : np->n_right)); - if (geqflag) - return (key > parent->n_key ? parent->n_next : parent); + if (np = (key > parent->n_key ? parent->n_next : parent)) + { + if (deltap) + *deltap = np->n_key - key; + return (np); + } + else return (0); +} + +/* Returns the smallest node >= key or the greatest node <= key, whichever + makes the smallest abs diff, |key - node.n_key|. Returns null only for + an empty tree. If deltap is not null, it will hold the signed diff + (negative for an undernode, i.e. when node < key). */ +t_qnode *qtree_closest(t_qtree *tree, double key, double *deltap) +{ + t_qnode *np, *parent; + if (!(np = tree->t_root)) + return (0); + do + if (np->n_key == key) + { + if (deltap) + *deltap = 0.; + return (np); + } + else parent = np; + while (np = (key < np->n_key ? np->n_left : np->n_right)); + if (key > parent->n_key) + { + if (np = parent->n_next) + { + double delta1 = key - parent->n_key; + double delta2 = np->n_key - key; + if (delta1 < delta2) + { + if (deltap) + *deltap = -delta1; + return (parent); + } + else + { + if (deltap) + *deltap = delta2; + return (np); + } + } + else + { + if (deltap) + *deltap = parent->n_key - key; + return (parent); + } + } else - return (key < parent->n_key ? parent->n_prev : parent); + { + if (np = parent->n_prev) + { + double delta1 = key - np->n_key; + double delta2 = parent->n_key - key; + if (delta1 < delta2) + { + if (deltap) + *deltap = -delta1; + return (np); + } + else + { + if (deltap) + *deltap = delta2; + return (parent); + } + } + else + { + if (deltap) + *deltap = parent->n_key - key; + return (parent); + } + } } -t_qnode *qtree_insert(t_qtree *tree, double key, int *foundp) +t_qnode *qtree_insert(t_qtree *tree, double key, + t_qnode *preexisting, int *foundp) { - return (qtree_doinsert(tree, key, 0, foundp)); + int found; + return (qtree_doinsert(tree, key, preexisting, 0, + (foundp ? foundp : &found))); } -t_qnode *qtree_multiinsert(t_qtree *tree, double key, int fifoflag) +t_qnode *qtree_multiinsert(t_qtree *tree, double key, + t_qnode *preexisting, int fifoflag) { int found; - return (qtree_doinsert(tree, key, (fifoflag ? - qtree_postinserthook : - qtree_preinserthook), &found)); + return (qtree_doinsert(tree, key, preexisting, + (fifoflag ? + qtree_postinserthook : + qtree_preinserthook), &found)); +} + +t_qnode *qtree_override(t_qtree *tree, t_qnode *oldnode, t_qnode *newnode) +{ + if (tree->t_nodesize) + { + loudbug_bug("qtree_override 1"); + return (0); + } + else + { + newnode->n_key = oldnode->n_key; + newnode->n_black = oldnode->n_black; + if (newnode->n_left = oldnode->n_left) + newnode->n_left->n_parent = newnode; + if (newnode->n_right = oldnode->n_right) + newnode->n_right->n_parent = newnode; + if (newnode->n_parent = oldnode->n_parent) + { + if (oldnode == newnode->n_parent->n_left) + newnode->n_parent->n_left = newnode; + else if (oldnode == newnode->n_parent->n_right) + newnode->n_parent->n_right = newnode; + else + loudbug_bug("qtree_override 2"); + } + if (newnode->n_prev = oldnode->n_prev) + newnode->n_prev->n_next = newnode; + if (newnode->n_next = oldnode->n_next) + newnode->n_next->n_prev = newnode; + if (tree->t_root == oldnode) + tree->t_root = newnode; + if (tree->t_first == oldnode) + tree->t_first = newnode; + if (tree->t_last == oldnode) + tree->t_last = newnode; + return (newnode); + } } t_qnode *qtree_insertfloat(t_qtree *tree, double key, t_float f, int replaceflag) { int found; - t_qnode *np = qtree_doinsert(tree, key, 0, &found); + t_qnode *np = qtree_doinsert(tree, key, 0, 0, &found); if (np && (!found || replaceflag)) { if (tree->t_valuetype == QTREETYPE_FLOAT) @@ -695,7 +857,7 @@ t_qnode *qtree_insertsymbol(t_qtree *tree, double key, t_symbol *s, int replaceflag) { int found; - t_qnode *np = qtree_doinsert(tree, key, 0, &found); + t_qnode *np = qtree_doinsert(tree, key, 0, 0, &found); if (np && (!found || replaceflag)) { if (tree->t_valuetype == QTREETYPE_SYMBOL) @@ -718,7 +880,7 @@ t_qnode *qtree_insertatom(t_qtree *tree, double key, t_atom *ap, int replaceflag) { int found; - t_qnode *np = qtree_doinsert(tree, key, 0, &found); + t_qnode *np = qtree_doinsert(tree, key, 0, 0, &found); if (np && (!found || replaceflag)) { if (tree->t_valuetype == QTREETYPE_ATOM) @@ -771,11 +933,11 @@ void qtree_initcustom(t_qtree *tree, size_t nodesize, int freecount) void qtree_clear(t_qtree *tree, int freecount) { t_qnode *np, *next = tree->t_first; - while (next) + while (np = next) { - np = next; next = next->n_next; - freebytes(np, tree->t_nodesize); + if (tree->t_nodesize) + freebytes(np, tree->t_nodesize); } qtree_doinit(tree, tree->t_valuetype, tree->t_nodesize, 0); } diff --git a/shared/common/qtree.h b/shared/common/qtree.h index 97c2906..18e4098 100644 --- a/shared/common/qtree.h +++ b/shared/common/qtree.h @@ -60,10 +60,15 @@ typedef struct _qtree typedef void (*t_qnode_vshowhook)(t_qnode *, char *, unsigned); t_qnode *qtree_search(t_qtree *tree, double key); -t_qnode *qtree_closest(t_qtree *tree, double key, int geqflag); +t_qnode *qtree_closestunder(t_qtree *tree, double key, double *deltap); +t_qnode *qtree_closestover(t_qtree *tree, double key, double *deltap); +t_qnode *qtree_closest(t_qtree *tree, double key, double *deltap); -t_qnode *qtree_insert(t_qtree *tree, double key, int *foundp); -t_qnode *qtree_multiinsert(t_qtree *tree, double key, int fifoflag); +t_qnode *qtree_insert(t_qtree *tree, double key, + t_qnode *preexisting, int *foundp); +t_qnode *qtree_multiinsert(t_qtree *tree, double key, + t_qnode *preexisting, int fifoflag); +t_qnode *qtree_override(t_qtree *tree, t_qnode *oldnode, t_qnode *newnode); t_qnode *qtree_insertfloat(t_qtree *tree, double key, t_float f, int replaceflag); t_qnode *qtree_insertsymbol(t_qtree *tree, double key, t_symbol *s, |